Skip to content

Commit

Permalink
New IP hashing
Browse files Browse the repository at this point in the history
- `inX_addr`:
  - Rework structure, separate IPv4 and IPv6 addresses
  - Fix #263: Use `hashword()` to hash the IP address
- `pcap`: Rework TCP state hash key
  • Loading branch information
jelu committed Jan 21, 2022
1 parent 687f600 commit 68cc9c7
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 86 deletions.
2 changes: 1 addition & 1 deletion src/asn_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ asn_get_from_message(dns_message* m)
MMDB_lookup_result_s r;

s.sin_family = AF_INET;
s.sin_addr = tm->src_ip_addr._.in4;
s.sin_addr = tm->src_ip_addr.in4;

r = MMDB_lookup_sockaddr(&mmdb, (struct sockaddr*)&s, &ret);
if (ret == MMDB_SUCCESS && r.found_entry) {
Expand Down
2 changes: 1 addition & 1 deletion src/country_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ country_get_from_message(dns_message* m)
MMDB_lookup_result_s r;

s.sin_family = AF_INET;
s.sin_addr = tm->src_ip_addr._.in4;
s.sin_addr = tm->src_ip_addr.in4;

r = MMDB_lookup_sockaddr(&mmdb, (struct sockaddr*)&s, &ret);
if (ret == MMDB_SUCCESS && r.found_entry) {
Expand Down
99 changes: 45 additions & 54 deletions src/inX_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,76 +37,68 @@
#include "config.h"

#include "inX_addr.h"
#include "hashtbl.h"

#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h> // For AF_ on BSDs

static unsigned char v4_in_v6_prefix[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };

static int
is_v4_in_v6(const struct in6_addr* addr)
{
return (0 == memcmp(addr, v4_in_v6_prefix, 12));
}

const char*
inXaddr_ntop(const inX_addr* a, char* buf, socklen_t len)
{
const char* p;
if (!is_v4_in_v6(&a->in6))
if (a->family == AF_INET6)
p = inet_ntop(AF_INET6, &a->in6, buf, len);
else
p = inet_ntop(AF_INET, &a->_.in4, buf, len);
p = inet_ntop(AF_INET, &a->in4, buf, len);
if (p)
return p;
return "[unprintable]";
}

int inXaddr_pton(const char* buf, inX_addr* a)
{
if (strchr(buf, ':'))
return inet_pton(AF_INET6, buf, a);
memcpy(a, v4_in_v6_prefix, 12);
return inet_pton(AF_INET, buf, &a->_.in4);
if (strchr(buf, ':')) {
a->family = AF_INET6;
return inet_pton(AF_INET6, buf, &a->in6);
}
a->family = AF_INET;
return inet_pton(AF_INET, buf, &a->in4);
}

unsigned int
inXaddr_hash(const inX_addr* a)
{
unsigned int lowest32;

if ((lowest32 = ntohl(a->_.in4.s_addr))) {
return lowest32;
}
if ((lowest32 = ntohl(a->_.pad2.s_addr))) {
return lowest32;
}
if ((lowest32 = ntohl(a->_.pad1.s_addr))) {
return lowest32;
if (a->family == AF_INET6) {
return hashword(a->in6.s6_addr32, 4, 0);
}
return ntohl(a->_.pad0.s_addr);
return hashword(&a->in4.s_addr, 1, 0);
}

int inXaddr_cmp(const inX_addr* a, const inX_addr* b)
{
if (ntohl(a->_.in4.s_addr) < ntohl(b->_.in4.s_addr))
return -1;
if (ntohl(a->_.in4.s_addr) > ntohl(b->_.in4.s_addr))
return 1;
if (is_v4_in_v6(&a->in6))
if (a->family == AF_INET6) {
if (ntohl(a->in6.s6_addr32[3]) < ntohl(b->in6.s6_addr32[3]))
return -1;
if (ntohl(a->in6.s6_addr32[3]) > ntohl(b->in6.s6_addr32[3]))
return 1;
if (ntohl(a->in6.s6_addr32[2]) < ntohl(b->in6.s6_addr32[2]))
return -1;
if (ntohl(a->in6.s6_addr32[2]) > ntohl(b->in6.s6_addr32[2]))
return 1;
if (ntohl(a->in6.s6_addr32[1]) < ntohl(b->in6.s6_addr32[1]))
return -1;
if (ntohl(a->in6.s6_addr32[1]) > ntohl(b->in6.s6_addr32[1]))
return 1;
if (ntohl(a->in6.s6_addr32[0]) < ntohl(b->in6.s6_addr32[0]))
return -1;
if (ntohl(a->in6.s6_addr32[0]) > ntohl(b->in6.s6_addr32[0]))
return 1;
return 0;
if (ntohl(a->_.pad2.s_addr) < ntohl(b->_.pad2.s_addr))
return -1;
if (ntohl(a->_.pad2.s_addr) > ntohl(b->_.pad2.s_addr))
return 1;
if (ntohl(a->_.pad1.s_addr) < ntohl(b->_.pad1.s_addr))
return -1;
if (ntohl(a->_.pad1.s_addr) > ntohl(b->_.pad1.s_addr))
return 1;
if (ntohl(a->_.pad0.s_addr) < ntohl(b->_.pad0.s_addr))
}
if (ntohl(a->in4.s_addr) < ntohl(b->in4.s_addr))
return -1;
if (ntohl(a->_.pad0.s_addr) > ntohl(b->_.pad0.s_addr))
if (ntohl(a->in4.s_addr) > ntohl(b->in4.s_addr))
return 1;
return 0;
}
Expand All @@ -115,37 +107,36 @@ inX_addr
inXaddr_mask(const inX_addr* a, const inX_addr* mask)
{
inX_addr masked;
masked._.in4.s_addr = a->_.in4.s_addr & mask->_.in4.s_addr;
if (is_v4_in_v6(&a->in6)) {
masked._.pad2.s_addr = a->_.pad2.s_addr;
masked._.pad1.s_addr = a->_.pad1.s_addr;
masked._.pad0.s_addr = a->_.pad0.s_addr;
if (a->family == AF_INET6) {
masked.family = AF_INET6;
masked.in6.s6_addr32[0] = a->in6.s6_addr32[0] & mask->in6.s6_addr32[0];
masked.in6.s6_addr32[1] = a->in6.s6_addr32[1] & mask->in6.s6_addr32[1];
masked.in6.s6_addr32[2] = a->in6.s6_addr32[2] & mask->in6.s6_addr32[2];
masked.in6.s6_addr32[3] = a->in6.s6_addr32[3] & mask->in6.s6_addr32[3];
} else {
masked._.pad2.s_addr = a->_.pad2.s_addr & mask->_.pad2.s_addr;
masked._.pad1.s_addr = a->_.pad1.s_addr & mask->_.pad1.s_addr;
masked._.pad0.s_addr = a->_.pad0.s_addr & mask->_.pad0.s_addr;
masked.family = AF_INET;
masked.in4.s_addr = a->in4.s_addr & mask->in4.s_addr;
}
return masked;
}

int inXaddr_version(const inX_addr* a)
{
if (!is_v4_in_v6(&a->in6))
if (a->family == AF_INET6)
return 6;
return 4;
}

int inXaddr_assign_v4(inX_addr* dst, const struct in_addr* src)
{
memcpy(dst, v4_in_v6_prefix, 12);
/* memcpy() instead of struct assignment in case src is not aligned */
memcpy(&dst->_.in4, src, sizeof(*src));
dst->family = AF_INET;
dst->in4 = *src;
return 0;
}

int inXaddr_assign_v6(inX_addr* dst, const struct in6_addr* src)
{
/* memcpy() instead of struct assignment in case src is not aligned */
memcpy(&dst->in6, src, sizeof(*src));
dst->family = AF_INET6;
dst->in6 = *src;
return 0;
}
14 changes: 6 additions & 8 deletions src/inX_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,14 @@
#define __dsc_inX_addr_h

#include <netinet/in.h>
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif

typedef union {
typedef struct {
int family;
struct in6_addr in6;
struct
{
struct in_addr pad0;
struct in_addr pad1;
struct in_addr pad2;
struct in_addr in4;
} _;
struct in_addr in4;
} inX_addr;

extern int inXaddr_version(const inX_addr*);
Expand Down
20 changes: 10 additions & 10 deletions src/ip_direction_index.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,24 +105,24 @@ int ip_local_address(const char* presentation, const char* mask)

if (bits > 96) {
bit_mask <<= 128 - bits;
n->mask._.in4.s_addr = htonl(bit_mask);
n->mask.in6.s6_addr32[3] = htonl(bit_mask);
} else {
n->mask._.in4.s_addr = 0;
n->mask.in6.s6_addr32[3] = 0;
if (bits > 64) {
bit_mask <<= 96 - bits;
n->mask._.pad2.s_addr = htonl(bit_mask);
n->mask.in6.s6_addr32[2] = htonl(bit_mask);
} else {
n->mask._.pad2.s_addr = 0;
n->mask.in6.s6_addr32[2] = 0;
if (bits > 32) {
bit_mask <<= 64 - bits;
n->mask._.pad1.s_addr = htonl(bit_mask);
n->mask.in6.s6_addr32[1] = htonl(bit_mask);
} else {
n->mask._.pad1.s_addr = 0;
n->mask.in6.s6_addr32[1] = 0;
if (bits) {
bit_mask <<= 32 - bits;
n->mask._.pad0.s_addr = htonl(bit_mask);
n->mask.in6.s6_addr32[0] = htonl(bit_mask);
} else {
n->mask._.pad0.s_addr = 0;
n->mask.in6.s6_addr32[0] = 0;
}
}
}
Expand All @@ -136,9 +136,9 @@ int ip_local_address(const char* presentation, const char* mask)

if (bits) {
bit_mask <<= 32 - bits;
n->mask._.in4.s_addr = htonl(bit_mask);
n->mask.in4.s_addr = htonl(bit_mask);
} else {
n->mask._.in4.s_addr = 0;
n->mask.in4.s_addr = 0;
}
}
} else if (inXaddr_pton(mask, &n->mask) != 1) {
Expand Down
39 changes: 27 additions & 12 deletions src/pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,33 @@ tcpstate_free(void* p)
xfree(p);
}

inline static void tcpkey_set(tcpHashkey_t* key, inX_addr src, uint16_t sport, inX_addr dst, uint16_t dport)
{
memset(key, 0, sizeof(*key));
key->src_ip_addr.family = src.family;
if (src.family == AF_INET6) {
key->src_ip_addr.in6 = src.in6;
} else {
key->src_ip_addr.in4 = src.in4;
}
key->sport = sport;

key->dst_ip_addr.family = dst.family;
if (dst.family == AF_INET6) {
key->dst_ip_addr.in6 = dst.in6;
} else {
key->dst_ip_addr.in4 = dst.in4;
}
key->dport = dport;
}

static unsigned int
tcp_hashfunc(const void* key)
{
tcpHashkey_t* k = (tcpHashkey_t*)key;
return (k->dport << 16) | k->sport | k->src_ip_addr._.in4.s_addr | k->dst_ip_addr._.in4.s_addr;
/* 32 low bits of ipv6 address are good enough for a hash */
if (!(sizeof(tcpHashkey_t) % 4)) {
return hashword(key, sizeof(tcpHashkey_t) / 4, 0);
}
return hashendian(key, sizeof(tcpHashkey_t), 0);
}

static int
Expand Down Expand Up @@ -541,10 +562,7 @@ pcap_tcp_handler(const struct tcphdr* tcp, int len, void* udata)
tm->dst_port = nptohs(&tcp->th_dport);
tm->proto = IPPROTO_TCP;

key.src_ip_addr = tm->src_ip_addr;
key.dst_ip_addr = tm->dst_ip_addr;
key.sport = tm->src_port;
key.dport = tm->dst_port;
tcpkey_set(&key, tm->src_ip_addr, tm->src_port, tm->dst_ip_addr, tm->dst_port);

if (debug_flag > 1) {
char src[128], dst[128];
Expand Down Expand Up @@ -590,11 +608,8 @@ pcap_tcp_handler(const struct tcphdr* tcp, int len, void* udata)
hash_remove(&key, tcpHash); /* this also frees tcpstate */

/* remove the state for the opposite direction */
key.src_ip_addr = tm->dst_ip_addr;
key.dst_ip_addr = tm->src_ip_addr;
key.sport = tm->dst_port;
key.dport = tm->src_port;
tcpstate = hash_find(&key, tcpHash);
tcpkey_set(&key, tm->dst_ip_addr, tm->dst_port, tm->src_ip_addr, tm->src_port);
tcpstate = hash_find(&key, tcpHash);
if (tcpstate) {
tcpList_remove(tcpstate);
hash_remove(&key, tcpHash); /* this also frees tcpstate */
Expand Down

0 comments on commit 68cc9c7

Please sign in to comment.