From 548a3b2c93aed79e39a34ee9dd4c68f43a27f363 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sun, 16 May 2010 15:20:24 +0200 Subject: [PATCH] Improve flow hash debugging functions. Make sure ICMP errors don't create flows. Handle ICMP DEST UNREACH errors in the flow they are sending the error about. --- src/decode-icmpv4.c | 27 +++--- src/decode-icmpv4.h | 31 ++++++- src/decode-ipv4.h | 5 ++ src/flow-hash.c | 203 +++++++++++++++++++++++++++++++++++++------- src/flow-hash.h | 11 ++- src/flow.c | 38 +++++++-- 6 files changed, 262 insertions(+), 53 deletions(-) diff --git a/src/decode-icmpv4.c b/src/decode-icmpv4.c index ffe71192ad..97acaafce7 100644 --- a/src/decode-icmpv4.c +++ b/src/decode-icmpv4.c @@ -71,8 +71,9 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) case IPPROTO_TCP: if (len >= IPV4_HEADER_LEN + TCP_HEADER_LEN ) { p->icmpv4vars.emb_tcph = (TCPHdr*)(partial_packet + IPV4_HEADER_LEN); - p->icmpv4vars.emb_sport = p->icmpv4vars.emb_tcph->th_sport; - p->icmpv4vars.emb_dport = p->icmpv4vars.emb_tcph->th_dport; + p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_tcph->th_sport); + p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_tcph->th_dport); + p->icmpv4vars.emb_ip4_proto = IPPROTO_TCP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->TCP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, @@ -88,8 +89,9 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t len ) case IPPROTO_UDP: if (len >= IPV4_HEADER_LEN + UDP_HEADER_LEN ) { p->icmpv4vars.emb_udph = (UDPHdr*)(partial_packet + IPV4_HEADER_LEN); - p->icmpv4vars.emb_sport = p->icmpv4vars.emb_udph->uh_sport; - p->icmpv4vars.emb_dport = p->icmpv4vars.emb_udph->uh_dport; + p->icmpv4vars.emb_sport = ntohs(p->icmpv4vars.emb_udph->uh_sport); + p->icmpv4vars.emb_dport = ntohs(p->icmpv4vars.emb_udph->uh_dport); + p->icmpv4vars.emb_ip4_proto = IPPROTO_UDP; SCLogDebug("DecodePartialIPV4: ICMPV4->IPV4->UDP header sport: " "%"PRIu8" dport %"PRIu8"", p->icmpv4vars.emb_sport, @@ -106,6 +108,7 @@ void DecodePartialIPV4( Packet* p, uint8_t* partial_packet, uint16_t 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"); @@ -160,16 +163,20 @@ void DecodeICMPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt break; case ICMP_DEST_UNREACH: - if (p->icmpv4h->code>NR_ICMP_UNREACH) { + if (p->icmpv4h->code > NR_ICMP_UNREACH) { DECODER_SET_EVENT(p,ICMPV4_UNKNOWN_CODE); } 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 ); + /* 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, p); + } + } } - /* ICMP ICMP_DEST_UNREACH influence TCP/UDP flows */ - FlowHandlePacket(tv, p); break; diff --git a/src/decode-icmpv4.h b/src/decode-icmpv4.h index 5dbe6af27c..2b93c1c17d 100644 --- a/src/decode-icmpv4.h +++ b/src/decode-icmpv4.h @@ -196,6 +196,7 @@ typedef struct ICMPV4Vars_ struct in_addr emb_ip4_src; struct in_addr emb_ip4_dst; uint8_t emb_ip4_hlen; + uint8_t emb_ip4_proto; /** TCP/UDP ports */ uint16_t emb_sport; @@ -207,7 +208,7 @@ typedef struct ICMPV4Vars_ /** macro for icmpv4 "type" access */ #define ICMPV4_GET_TYPE(p) (p)->icmpv4h->type /** macro for icmpv4 "code" access */ - #define ICMPV4_GET_CODE(p) (p)->icmpv4h->code +#define ICMPV4_GET_CODE(p) (p)->icmpv4h->code /** macro for icmpv4 "csum" access */ #define ICMPV4_GET_CSUM(p) (p)->icmpv4h->csum @@ -228,7 +229,7 @@ typedef struct ICMPV4Vars_ #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_ip6_proto_next +#define ICMPV4_GET_EMB_PROTO(p) (p)->icmpv4vars.emb_ip4_proto /** macro for icmpv4 embedded "ipv4h" header access */ #define ICMPV4_GET_EMB_IPV4(p) (p)->icmpv4vars.emb_ipv4h /** macro for icmpv4 embedded "tcph" header access */ @@ -238,6 +239,32 @@ typedef struct ICMPV4Vars_ /** macro for icmpv4 embedded "icmpv4h" header access */ #define ICMPV4_GET_EMB_ICMPV4H(p) (p)->icmpv4vars.emb_icmpv4h +/** macro for checking if a ICMP DEST UNREACH packet is valid for use + * in other parts of the engine, such as the flow engine. + * + * \warning use only _after_ the decoder has processed the packet + */ +#define ICMPV4_DEST_UNREACH_IS_VALID(p) (((p)->icmpv4h != NULL) && \ + (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH) && \ + (ICMPV4_GET_EMB_IPV4((p)) != NULL) && \ + ((ICMPV4_GET_EMB_TCP((p)) != NULL) || \ + (ICMPV4_GET_EMB_UDP((p)) != NULL))) + +/** + * marco for checking if a ICMP packet is an error message or an + * query message. + * + * \todo This check is used in the flow engine and needs to be as + * cheap as possible. Consider setting a bitflag at the decoder + * stage so we can to a bit check instead of the more expensive + * check below. + */ +#define ICMPV4_IS_ERROR_MSG(p) (ICMPV4_GET_TYPE((p)) == ICMP_DEST_UNREACH || \ + ICMPV4_GET_TYPE((p)) == ICMP_SOURCE_QUENCH || \ + ICMPV4_GET_TYPE((p)) == ICMP_REDIRECT || \ + ICMPV4_GET_TYPE((p)) == ICMP_TIME_EXCEEDED || \ + ICMPV4_GET_TYPE((p)) == ICMP_PARAMETERPROB) + typedef struct ICMPV4Cache_ { /* checksum computed over the icmpv4 packet */ int32_t comp_csum; diff --git a/src/decode-ipv4.h b/src/decode-ipv4.h index 8fdf204291..6edb4b598c 100644 --- a/src/decode-ipv4.h +++ b/src/decode-ipv4.h @@ -92,6 +92,11 @@ typedef struct IPV4Hdr_ #define IPV4_GET_RAW_IPSRC(ip4h) ((ip4h)->ip_src) #define IPV4_GET_RAW_IPDST(ip4h) ((ip4h)->ip_dst) +/** return the raw (directly from the header) src ip as uint32_t */ +#define IPV4_GET_RAW_IPSRC_U32(ip4h) (uint32_t)((ip4h)->ip_src.s_addr) +/** return the raw (directly from the header) dst ip as uint32_t */ +#define IPV4_GET_RAW_IPDST_U32(ip4h) (uint32_t)((ip4h)->ip_dst.s_addr) + /* we need to change them as well as get them */ #define IPV4_SET_RAW_VER(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0x0f) | (value << 4))) #define IPV4_SET_RAW_HLEN(ip4h, value) ((ip4h)->ip_verhl = (((ip4h)->ip_verhl & 0xf0) | (value & 0x0f))) diff --git a/src/flow-hash.c b/src/flow-hash.c index d1f5fc59be..72100b11d8 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -34,10 +34,9 @@ #include "flow-util.h" #include "flow-private.h" +#include "util-time.h" #include "util-debug.h" -//#define FLOW_DEBUG_STATS - #ifdef FLOW_DEBUG_STATS #define FLOW_DEBUG_STATS_PROTO_ALL 0 #define FLOW_DEBUG_STATS_PROTO_TCP 1 @@ -47,6 +46,7 @@ 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 { \ @@ -54,15 +54,18 @@ static 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 (f->proto == IPPROTO_TCP) { \ + 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 (f->proto == IPPROTO_UDP) {\ + } 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 (f->proto == IPPROTO_ICMP) {\ + } 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); \ @@ -71,40 +74,58 @@ static SCSpinlock flow_hash_count_lock; #define FlowHashCountInit uint64_t _flow_hash_counter = 0 #define FlowHashCountIncr _flow_hash_counter++; -#else - -#define FlowHashCountUpdate -#define FlowHashCountInit -#define FlowHashCountIncr - -#endif /* FLOW_DEBUG_STATS */ - void FlowHashDebugInit(void) { #ifdef FLOW_DEBUG_STATS SCSpinInit(&flow_hash_count_lock, 0); #endif + flow_hash_count_fp = fopen("flow-debug.log", "w+"); } -void FlowHashDebugDeinit(void) { +void FlowHashDebugPrint(uint32_t ts) { #ifdef FLOW_DEBUG_STATS - SCSpinDestroy(&flow_hash_count_lock); - SCLogInfo("TCP %"PRIu64" %"PRIu64, flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP], flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP]); + 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": all %02.3f, tcp %02.3f, udp %02.3f, icmp %02.3f, other %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 FlowHashDebugPrint(void) { +void FlowHashDebugDeinit(void) { #ifdef FLOW_DEBUG_STATS - float avg_all, avg_tcp, avg_udp, avg_icmp; - SCSpinLock(&flow_hash_count_lock); - avg_all = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ALL]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ALL])); - avg_tcp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_TCP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_TCP])); - avg_udp = (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_UDP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_UDP])); - avg_icmp= (float)(flow_hash_loop_count[FLOW_DEBUG_STATS_PROTO_ICMP]/(float)(flow_hash_count[FLOW_DEBUG_STATS_PROTO_ICMP])); - SCSpinUnlock(&flow_hash_count_lock); - SCLogInfo("Avg flowbucket walk: all %02.3f, tcp %02.3f, udp %02.3f, icmp %02.3f", avg_all, avg_tcp, avg_udp, avg_icmp); + 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 */ + /* calculate the hash key for this packet * * we're using: @@ -115,16 +136,49 @@ void FlowHashDebugPrint(void) { * destination address * recursion level -- for tunnels, make sure different tunnel layers can * never get mixed up. + * + * For ICMP we only consider UNREACHABLE errors atm. */ uint32_t FlowGetKey(Packet *p) { FlowKey *k = (FlowKey *)p; uint32_t key; - if (p->ip4h != NULL) - key = (flow_config.hash_rand + k->proto + k->sp + k->dp + \ - k->src.addr_data32[0] + k->dst.addr_data32[0] + \ - k->recursion_level) % flow_config.hash_size; - else if (p->ip6h != NULL) + if (p->ip4h != NULL) { + if (p->tcph != NULL || p->udph != NULL) { + key = (flow_config.hash_rand + k->proto + k->sp + k->dp + \ + k->src.addr_data32[0] + k->dst.addr_data32[0] + \ + k->recursion_level) % flow_config.hash_size; +/* + SCLogDebug("TCP/UCP key %"PRIu32, key); + + SCLogDebug("proto %u, sp %u, dp %u, src %u, dst %u, reclvl %u", + k->proto, k->sp, k->dp, k->src.addr_data32[0], k->dst.addr_data32[0], + k->recursion_level); +*/ + } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { +// SCLogDebug("valid ICMPv4 DEST UNREACH error packet"); + + key = (flow_config.hash_rand + ICMPV4_GET_EMB_PROTO(p) + + p->icmpv4vars.emb_sport + \ + p->icmpv4vars.emb_dport + \ + IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)) + \ + IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)) + \ + k->recursion_level) % flow_config.hash_size; +/* + SCLogDebug("ICMP DEST UNREACH key %"PRIu32, key); + + SCLogDebug("proto %u, sp %u, dp %u, src %u, dst %u, reclvl %u", + ICMPV4_GET_EMB_PROTO(p), p->icmpv4vars.emb_sport, + p->icmpv4vars.emb_dport, IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)), + IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)), k->recursion_level); +*/ + } else { + key = (flow_config.hash_rand + k->proto + \ + k->src.addr_data32[0] + k->dst.addr_data32[0] + \ + k->recursion_level) % flow_config.hash_size; + + } + } else if (p->ip6h != NULL) key = (flow_config.hash_rand + k->proto + k->sp + k->dp + \ k->src.addr_data32[0] + k->src.addr_data32[1] + \ k->src.addr_data32[2] + k->src.addr_data32[3] + \ @@ -149,6 +203,79 @@ uint32_t FlowGetKey(Packet *p) { (f1)->proto == (f2)->proto && \ (f1)->recursion_level == (f2)->recursion_level) +/** + * \brief See if a ICMP packet belongs to a flow by comparing the embedded + * packet in the ICMP error packet to the flow. + * + * \param f flow + * \param p ICMP packet + * + * \retval 1 match + * \retval 0 no match + */ +static inline int FlowCompareICMPv4(Flow *f, Packet *p) { + if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { + /* first check the direction of the flow, in other words, the client -> + * server direction as it's most likely the ICMP error will be a + * response to the clients traffic */ + if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && + (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && + f->sp == p->icmpv4vars.emb_sport && + f->dp == p->icmpv4vars.emb_dport && + f->proto == ICMPV4_GET_EMB_PROTO(p) && + f->recursion_level == p->recursion_level) + { + return 1; + + /* check the less likely case where the ICMP error was a response to + * a packet from the server. */ + } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) && + (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) && + f->dp == p->icmpv4vars.emb_sport && + f->sp == p->icmpv4vars.emb_dport && + f->proto == ICMPV4_GET_EMB_PROTO(p) && + f->recursion_level == p->recursion_level) + { + return 1; + } + + /* no match, fall through */ + } else { + /* just treat ICMP as a normal proto for now */ + return CMP_FLOW(f, p); + } + + return 0; +} + +static inline int FlowCompare(Flow *f, Packet *p) { + if (p->proto == IPPROTO_ICMP) { + return FlowCompareICMPv4(f, p); + } else { + return CMP_FLOW(f, p); + } +} + +/** + * \brief Check if we should create a flow based on a packet + * + * We use this check to filter out flow creation based on: + * - ICMP error messages + * + * \param p packet + * \retval 1 true + * \retval 0 false + */ +static inline int FlowCreateCheck(Packet *p) { + if (PKT_IS_ICMPV4(p)) { + if (ICMPV4_IS_ERROR_MSG(p)) { + return 0; + } + } + + return 1; +} + /* FlowGetFlowFromHash * * Hash retrieval function for flows. Looks up the hash bucket containing the @@ -178,6 +305,12 @@ Flow *FlowGetFlowFromHash (Packet *p) /* see if the bucket already has a flow */ if (fb->f == NULL) { + if (FlowCreateCheck(p) == 0) { + SCSpinUnlock(&fb->s); + FlowHashCountUpdate; + return NULL; + } + /* no, so get a new one */ f = fb->f = FlowDequeue(&flow_spare_q); if (f == NULL) { @@ -212,7 +345,7 @@ Flow *FlowGetFlowFromHash (Packet *p) SCMutexLock(&f->m); /* see if this is the flow we are looking for */ - if (CMP_FLOW(f, p) == 0) { + if (FlowCompare(f, p) == 0) { Flow *pf = NULL; /* previous flow */ SCMutexUnlock(&f->m); @@ -223,6 +356,12 @@ Flow *FlowGetFlowFromHash (Packet *p) f = f->hnext; if (f == NULL) { + if (FlowCreateCheck(p) == 0) { + SCSpinUnlock(&fb->s); + FlowHashCountUpdate; + return NULL; + } + /* get us a new one and put it and the list tail */ f = pf->hnext = FlowDequeue(&flow_spare_q); if (f == NULL) { @@ -254,7 +393,7 @@ Flow *FlowGetFlowFromHash (Packet *p) SCMutexLock(&f->m); - if (CMP_FLOW(f, p) != 0) { + 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; diff --git a/src/flow-hash.h b/src/flow-hash.h index 14b7c46907..1b8b374f61 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -38,9 +38,18 @@ typedef struct FlowBucket_ { Flow *FlowGetFlowFromHash(Packet *); +/** 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(void); +void FlowHashDebugPrint(uint32_t); +#else +#define FlowHashDebugInit(...) +#define FlowHashDebugPrint(...) +#define FlowHashDebugDeinit(...) +#endif #endif /* __FLOW_HASH_H__ */ diff --git a/src/flow.c b/src/flow.c index 7e05518ff4..bbd23f03d1 100644 --- a/src/flow.c +++ b/src/flow.c @@ -382,6 +382,24 @@ static inline int FlowGetPacketDirection(Flow *f, Packet *p) { return TOSERVER; } +/** + * \brief Check to update "seen" flags + * + * \param p packet + * + * \retval 1 true + * \retval 0 false + */ +static inline int FlowUpdateSeenFlag(Packet *p) { + if (PKT_IS_ICMPV4(p)) { + if (ICMPV4_IS_ERROR_MSG(p)) { + return 0; + } + } + + return 1; +} + /** \brief Entry point for packet flow handling * * This is called for every packet. @@ -405,11 +423,15 @@ void FlowHandlePacket (ThreadVars *tv, Packet *p) /* update flags and counters */ if (FlowGetPacketDirection(f,p) == TOSERVER) { - f->flags |= FLOW_TO_DST_SEEN; + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_DST_SEEN; + } f->todstpktcnt++; p->flowflags |= FLOW_PKT_TOSERVER; } else { - f->flags |= FLOW_TO_SRC_SEEN; + if (FlowUpdateSeenFlag(p)) { + f->flags |= FLOW_TO_SRC_SEEN; + } f->tosrcpktcnt++; p->flowflags |= FLOW_PKT_TOCLIENT; } @@ -659,6 +681,7 @@ void *FlowManagerThread(void *td) uint32_t established_cnt = 0, new_cnt = 0, closing_cnt = 0, nowcnt; uint32_t sleeping = 0; uint8_t emerg = FALSE; + uint32_t last_sec = 0; memset(&ts, 0, sizeof(ts)); @@ -679,22 +702,21 @@ void *FlowManagerThread(void *td) if (sleeping >= 100 || flow_flags & FLOW_EMERGENCY) { - FlowHashDebugPrint(); - - /*uint32_t timeout_new = flow_config.timeout_new; - uint32_t timeout_est = flow_config.timeout_est; - printf("The Timeout values are %" PRIu32" and %" - PRIu32"\n", timeout_est, timeout_new);*/ if (flow_flags & FLOW_EMERGENCY) { emerg = TRUE; SCLogDebug("Flow emergency mode entered..."); } /* Get the time */ + last_sec = (uint32_t)ts.tv_sec; memset(&ts, 0, sizeof(ts)); TimeGet(&ts); SCLogDebug("ts %" PRIdMAX "", (intmax_t)ts.tv_sec); + if (((uint32_t)ts.tv_sec - last_sec) > 60) { + FlowHashDebugPrint((uint32_t)ts.tv_sec); + } + /* see if we still have enough spare flows */ FlowUpdateSpareFlows();