aboutgitcodebugslistschat
path: root/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tcp.c')
-rw-r--r--tcp.c78
1 files changed, 71 insertions, 7 deletions
diff --git a/tcp.c b/tcp.c
index f1de9cf..6c6a6dd 100644
--- a/tcp.c
+++ b/tcp.c
@@ -304,8 +304,9 @@
#include <stddef.h>
#include <string.h>
#include <sys/epoll.h>
-#include <sys/types.h>
+#include <sys/random.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -315,6 +316,7 @@
#include "passt.h"
#include "tap.h"
#include "util.h"
+#include "siphash.h"
/* Approximately maximum number of open descriptors per process */
#define MAX_CONNS (256 * 1024)
@@ -430,6 +432,7 @@ struct tcp_conn {
static char sock_buf[MAX_WINDOW];
static uint8_t tcp_act[MAX_CONNS / 8] = { 0 };
static struct tcp_conn tc[MAX_CONNS];
+static uint64_t hash_secret[2];
static int tcp_send_to_tap(struct ctx *c, int s, int flags, char *in, int len);
@@ -677,6 +680,60 @@ static void tcp_clamp_window(int s, struct tcphdr *th, int len, int init)
}
/**
+ * tcp_seq_init() - Calculate initial sequence number according to RFC 6528
+ * @c: Execution context
+ * @af: Address family, AF_INET or AF_INET6
+ * @addr: Remote address, pointer to sin_addr or sin6_addr
+ * @dstport: Destination port, connection-wise, network order
+ * @srcport: Source port, connection-wise, network order
+ *
+ * Return: initial TCP sequence
+ */
+static uint32_t tcp_seq_init(struct ctx *c, int af, void *addr,
+ in_port_t dstport, in_port_t srcport)
+{
+ struct timespec ts = { 0 };
+ uint32_t ns, seq;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ 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 = *(struct in_addr *)c->addr4,
+ .dstport = dstport,
+ };
+
+ seq = siphash_12b((uint8_t *)&in, 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->addr6,
+ .dstport = dstport,
+ };
+
+ seq = siphash_36b((uint8_t *)&in, hash_secret);
+ }
+
+ ns = ts.tv_sec * 1E9;
+ ns += ts.tv_nsec >> 5; /* 32ns ticks, overflows 32 bits every 137s */
+
+ return seq + ns;
+}
+
+/**
* tcp_conn_from_tap() - Handle connection request (SYN segment) from tap
* @c: Execution context
* @af: Address family, AF_INET or AF_INET6
@@ -744,9 +801,8 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr,
tc[s].seq_from_tap = tc[s].seq_init_from_tap + 1;
tc[s].seq_ack_to_tap = tc[s].seq_from_tap;
- /* TODO: RFC 6528 with SipHash, worth it? */
- tc[s].seq_to_tap = 0;
- tc[s].seq_ack_from_tap = tc[s].seq_to_tap;
+ tc[s].seq_to_tap = tcp_seq_init(c, af, addr, th->dest, th->source);
+ tc[s].seq_ack_from_tap = tc[s].seq_to_tap + 1;
if (connect(s, sa, sl)) {
if (errno != EINPROGRESS) {
@@ -827,6 +883,10 @@ static void tcp_conn_from_sock(struct ctx *c, int fd)
tc[s].sock_port = sa4->sin_port;
tc[s].tap_port = ((struct sockaddr_in *)&sa_l)->sin_port;
+
+ tc[s].seq_to_tap = tcp_seq_init(c, AF_INET, &sa4->sin_addr,
+ tc[s].sock_port,
+ tc[s].tap_port);
} else if (sa_l.ss_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&sa_r;
@@ -834,10 +894,12 @@ static void tcp_conn_from_sock(struct ctx *c, int fd)
tc[s].sock_port = sa6->sin6_port;
tc[s].tap_port = ((struct sockaddr_in6 *)&sa_l)->sin6_port;
+
+ tc[s].seq_to_tap = tcp_seq_init(c, AF_INET6, &sa6->sin6_addr,
+ tc[s].sock_port,
+ tc[s].tap_port);
}
- /* TODO: RFC 6528 with SipHash, worth it? */
- tc[s].seq_to_tap = 0;
tc[s].seq_ack_from_tap = tc[s].seq_to_tap + 1;
tc[s].tap_window = WINDOW_DEFAULT;
@@ -1230,7 +1292,7 @@ void tcp_sock_handler(struct ctx *c, int s, uint32_t events)
}
/**
- * tcp_sock_init() - Create and bind listening sockets for inbound connections
+ * tcp_sock_init() - Bind sockets for inbound connections, get key for sequence
* @c: Execution context
*
* Return: 0 on success, -1 on failure
@@ -1246,6 +1308,8 @@ int tcp_sock_init(struct ctx *c)
return -1;
}
+ getrandom(hash_secret, sizeof(hash_secret), GRND_RANDOM);
+
return 0;
}