|
|
|
@ -40,6 +40,8 @@
|
|
|
|
|
#include "util-time.h"
|
|
|
|
|
#include "util-debug.h"
|
|
|
|
|
|
|
|
|
|
#include "util-hash-lookup3.h"
|
|
|
|
|
|
|
|
|
|
#define FLOW_DEFAULT_FLOW_PRUNE 5
|
|
|
|
|
|
|
|
|
|
SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx);
|
|
|
|
@ -139,6 +141,54 @@ void FlowHashDebugDeinit(void) {
|
|
|
|
|
|
|
|
|
|
#endif /* FLOW_DEBUG_STATS */
|
|
|
|
|
|
|
|
|
|
/** \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.
|
|
|
|
|
*/
|
|
|
|
|
static inline int FlowHashRawAddressIPv6GtU32(uint32_t *a, 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct FlowHashKey4_ {
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
uint32_t src, dst;
|
|
|
|
|
uint16_t sp, dp;
|
|
|
|
|
uint16_t proto; /**< u16 so proto and recur add up to u32 */
|
|
|
|
|
uint16_t recur; /**< u16 so proto and recur add up to u32 */
|
|
|
|
|
};
|
|
|
|
|
uint32_t u32[4];
|
|
|
|
|
};
|
|
|
|
|
} FlowHashKey4;
|
|
|
|
|
|
|
|
|
|
typedef struct FlowHashKey6_ {
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
uint32_t src[4], dst[4];
|
|
|
|
|
uint16_t sp, dp;
|
|
|
|
|
uint16_t proto; /**< u16 so proto and recur add up to u32 */
|
|
|
|
|
uint16_t recur; /**< u16 so proto and recur add up to u32 */
|
|
|
|
|
};
|
|
|
|
|
uint32_t u32[10];
|
|
|
|
|
};
|
|
|
|
|
} FlowHashKey6;
|
|
|
|
|
|
|
|
|
|
/* calculate the hash key for this packet
|
|
|
|
|
*
|
|
|
|
|
* we're using:
|
|
|
|
@ -152,53 +202,107 @@ void FlowHashDebugDeinit(void) {
|
|
|
|
|
*
|
|
|
|
|
* For ICMP we only consider UNREACHABLE errors atm.
|
|
|
|
|
*/
|
|
|
|
|
uint32_t FlowGetKey(Packet *p) {
|
|
|
|
|
FlowKey *k = (FlowKey *)p;
|
|
|
|
|
static inline uint32_t FlowGetKey(Packet *p) {
|
|
|
|
|
uint32_t key;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
*/
|
|
|
|
|
FlowHashKey4 fhk;
|
|
|
|
|
if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
|
|
|
|
|
fhk.src = p->src.addr_data32[0];
|
|
|
|
|
fhk.dst = p->dst.addr_data32[0];
|
|
|
|
|
} else {
|
|
|
|
|
fhk.src = p->dst.addr_data32[0];
|
|
|
|
|
fhk.dst = p->src.addr_data32[0];
|
|
|
|
|
}
|
|
|
|
|
if (p->sp > p->dp) {
|
|
|
|
|
fhk.sp = p->sp;
|
|
|
|
|
fhk.dp = p->dp;
|
|
|
|
|
} else {
|
|
|
|
|
fhk.sp = p->dp;
|
|
|
|
|
fhk.dp = p->sp;
|
|
|
|
|
}
|
|
|
|
|
fhk.proto = (uint16_t)p->proto;
|
|
|
|
|
fhk.recur = (uint16_t)p->recursion_level;
|
|
|
|
|
|
|
|
|
|
uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand);
|
|
|
|
|
key = hash % flow_config.hash_size;
|
|
|
|
|
|
|
|
|
|
} 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);
|
|
|
|
|
*/
|
|
|
|
|
uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p));
|
|
|
|
|
uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p));
|
|
|
|
|
FlowHashKey4 fhk;
|
|
|
|
|
if (psrc > pdst) {
|
|
|
|
|
fhk.src = psrc;
|
|
|
|
|
fhk.dst = pdst;
|
|
|
|
|
} else {
|
|
|
|
|
fhk.src = pdst;
|
|
|
|
|
fhk.dst = psrc;
|
|
|
|
|
}
|
|
|
|
|
if (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport) {
|
|
|
|
|
fhk.sp = p->icmpv4vars.emb_sport;
|
|
|
|
|
fhk.dp = p->icmpv4vars.emb_dport;
|
|
|
|
|
} else {
|
|
|
|
|
fhk.sp = p->icmpv4vars.emb_dport;
|
|
|
|
|
fhk.dp = p->icmpv4vars.emb_sport;
|
|
|
|
|
}
|
|
|
|
|
fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p);
|
|
|
|
|
fhk.recur = (uint16_t)p->recursion_level;
|
|
|
|
|
|
|
|
|
|
uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand);
|
|
|
|
|
key = hash % flow_config.hash_size;
|
|
|
|
|
|
|
|
|
|
} 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;
|
|
|
|
|
FlowHashKey4 fhk;
|
|
|
|
|
if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
|
|
|
|
|
fhk.src = p->src.addr_data32[0];
|
|
|
|
|
fhk.dst = p->dst.addr_data32[0];
|
|
|
|
|
} else {
|
|
|
|
|
fhk.src = p->dst.addr_data32[0];
|
|
|
|
|
fhk.dst = p->src.addr_data32[0];
|
|
|
|
|
}
|
|
|
|
|
fhk.sp = 0xfeed;
|
|
|
|
|
fhk.dp = 0xbeef;
|
|
|
|
|
fhk.proto = (uint16_t)p->proto;
|
|
|
|
|
fhk.recur = (uint16_t)p->recursion_level;
|
|
|
|
|
|
|
|
|
|
uint32_t hash = hashword(fhk.u32, 4, flow_config.hash_rand);
|
|
|
|
|
key = hash % flow_config.hash_size;
|
|
|
|
|
}
|
|
|
|
|
} else if (p->ip6h != NULL) {
|
|
|
|
|
FlowHashKey6 fhk;
|
|
|
|
|
if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
|
|
|
|
|
fhk.src[0] = p->src.addr_data32[0];
|
|
|
|
|
fhk.src[1] = p->src.addr_data32[1];
|
|
|
|
|
fhk.src[2] = p->src.addr_data32[2];
|
|
|
|
|
fhk.src[3] = p->src.addr_data32[3];
|
|
|
|
|
fhk.dst[0] = p->dst.addr_data32[0];
|
|
|
|
|
fhk.dst[1] = p->dst.addr_data32[1];
|
|
|
|
|
fhk.dst[2] = p->dst.addr_data32[2];
|
|
|
|
|
fhk.dst[3] = p->dst.addr_data32[3];
|
|
|
|
|
} else {
|
|
|
|
|
fhk.src[0] = p->dst.addr_data32[0];
|
|
|
|
|
fhk.src[1] = p->dst.addr_data32[1];
|
|
|
|
|
fhk.src[2] = p->dst.addr_data32[2];
|
|
|
|
|
fhk.src[3] = p->dst.addr_data32[3];
|
|
|
|
|
fhk.dst[0] = p->src.addr_data32[0];
|
|
|
|
|
fhk.dst[1] = p->src.addr_data32[1];
|
|
|
|
|
fhk.dst[2] = p->src.addr_data32[2];
|
|
|
|
|
fhk.dst[3] = p->src.addr_data32[3];
|
|
|
|
|
}
|
|
|
|
|
} 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] + \
|
|
|
|
|
k->dst.addr_data32[0] + k->dst.addr_data32[1] + \
|
|
|
|
|
k->dst.addr_data32[2] + k->dst.addr_data32[3] + \
|
|
|
|
|
k->recursion_level) % flow_config.hash_size;
|
|
|
|
|
else
|
|
|
|
|
if (p->sp > p->dp) {
|
|
|
|
|
fhk.sp = p->sp;
|
|
|
|
|
fhk.dp = p->dp;
|
|
|
|
|
} else {
|
|
|
|
|
fhk.sp = p->dp;
|
|
|
|
|
fhk.dp = p->sp;
|
|
|
|
|
}
|
|
|
|
|
fhk.proto = (uint16_t)p->proto;
|
|
|
|
|
fhk.recur = (uint16_t)p->recursion_level;
|
|
|
|
|
|
|
|
|
|
uint32_t hash = hashword(fhk.u32, 10, flow_config.hash_rand);
|
|
|
|
|
key = hash % flow_config.hash_size;
|
|
|
|
|
} else
|
|
|
|
|
key = 0;
|
|
|
|
|
|
|
|
|
|
return key;
|
|
|
|
|