#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);
#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:
*
* 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;