tcp_seq_init() has separate paths for IPv4 and IPv6 addresses. Convert it to convert IPv4 addresses to IPv4-mapped IPv6 addresses then compute the siphash as for IPv6. This is slightly simpler, and means that "true" IPv4 connections and "IPv6" connections using mapped addresses will have compatible sequence numbers. This will allow additional improvements in future. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- siphash.c | 1 + tcp.c | 46 +++++++++++++++++++--------------------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/siphash.c b/siphash.c index 516a508..811918b 100644 --- a/siphash.c +++ b/siphash.c @@ -123,6 +123,7 @@ uint64_t siphash_8b(const uint8_t *in, const uint64_t *k) * * Return: 32 bits obtained by XORing the two halves of the 64-bit hash output */ +/* cppcheck-suppress unusedFunction */ uint32_t siphash_12b(const uint8_t *in, const uint64_t *k) { uint32_t *in32 = (uint32_t *)in; diff --git a/tcp.c b/tcp.c index 6634abb..b9d0510 100644 --- a/tcp.c +++ b/tcp.c @@ -2011,38 +2011,30 @@ static uint32_t tcp_seq_init(const struct ctx *c, int af, const void *addr, in_port_t dstport, in_port_t srcport, const struct timespec *now) { + struct { + struct in6_addr src; + in_port_t srcport; + struct in6_addr dst; + in_port_t dstport; + } __attribute__((__packed__)) in = { + .srcport = srcport, + .dstport = dstport, + }; uint32_t ns, seq = 0; if (af == AF_INET) { - struct { - struct in_addr src; - in_port_t srcport; - struct in_addr dst; - in_port_t dstport; - } __attribute__((__packed__)) in = { - .src = *(struct in_addr *)addr, - .srcport = srcport, - .dst = c->ip4.addr, - .dstport = dstport, - }; - - seq = siphash_12b((uint8_t *)&in, c->tcp.hash_secret); - } else if (af == AF_INET6) { - struct { - struct in6_addr src; - in_port_t srcport; - struct in6_addr dst; - in_port_t dstport; - } __attribute__((__packed__)) in = { - .src = *(struct in6_addr *)addr, - .srcport = srcport, - .dst = c->ip6.addr, - .dstport = dstport, - }; - - seq = siphash_36b((uint8_t *)&in, c->tcp.hash_secret); + struct in6_addr tmp; + encode_ip4mapped_ip6(&tmp, addr); + in.src = tmp; + encode_ip4mapped_ip6(&tmp, &c->ip4.addr); + in.dst = tmp; + } else { + in.src = *(struct in6_addr *)addr; + in.dst = c->ip6.addr; } + seq = siphash_36b((uint8_t *)&in, c->tcp.hash_secret); + ns = now->tv_sec * 1E9; ns += now->tv_nsec >> 5; /* 32ns ticks, overflows 32 bits every 137s */ -- 2.38.1