From 16b08367a57f5a01af05d1067e2f77b04251e9b7 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Mon, 26 Jul 2021 07:30:57 +0200 Subject: tap: Fill the IPv6 flow label field to represent flow association This isn't optional: TCP streams must carry a unique, hard-to-guess, non-zero label for each direction. Linux, probably among others, will otherwise refuse to associate packets in a given stream to the same connection. Signed-off-by: Stefano Brivio --- dhcpv6.c | 4 ++-- icmp.c | 4 ++-- tap.c | 18 ++++++++++++++---- tap.h | 2 +- tcp.c | 7 ++++++- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/dhcpv6.c b/dhcpv6.c index 31ef66d..f982cde 100644 --- a/dhcpv6.c +++ b/dhcpv6.c @@ -520,7 +520,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len) resp_not_on_link.hdr.xid = mh->xid; tap_ip_send(c, &c->gw6, IPPROTO_UDP, - (char *)&resp_not_on_link, n); + (char *)&resp_not_on_link, n, mh->xid); return 1; } @@ -569,7 +569,7 @@ int dhcpv6(struct ctx *c, struct ethhdr *eh, size_t len) resp.hdr.xid = mh->xid; - tap_ip_send(c, &c->gw6, IPPROTO_UDP, (char *)&resp, n); + tap_ip_send(c, &c->gw6, IPPROTO_UDP, (char *)&resp, n, mh->xid); c->addr6_seen = c->addr6; return 1; diff --git a/icmp.c b/icmp.c index 8f2fdb2..57d954a 100644 --- a/icmp.c +++ b/icmp.c @@ -98,7 +98,7 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events, icmp_id_map[V6][id].seq = seq; } - tap_ip_send(c, &sr6->sin6_addr, IPPROTO_ICMPV6, buf, n); + tap_ip_send(c, &sr6->sin6_addr, IPPROTO_ICMPV6, buf, n, 0); } else { struct sockaddr_in *sr4 = (struct sockaddr_in *)&sr; struct icmphdr *ih = (struct icmphdr *)buf; @@ -115,7 +115,7 @@ void icmp_sock_handler(struct ctx *c, union epoll_ref ref, uint32_t events, memcpy(&a6.s6_addr[12], &sr4->sin_addr, sizeof(sr4->sin_addr)); - tap_ip_send(c, &a6, IPPROTO_ICMP, buf, n); + tap_ip_send(c, &a6, IPPROTO_ICMP, buf, n, 0); } } diff --git a/tap.c b/tap.c index 08b85ff..9fc84c1 100644 --- a/tap.c +++ b/tap.c @@ -91,9 +91,10 @@ int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre) * @proto: L4 protocol number * @in: Payload * @len: L4 payload length + * @flow: Flow label for TCP over IPv6 */ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto, - char *in, size_t len) + char *in, size_t len, uint32_t flow) { char buf[USHRT_MAX]; char *pkt = buf + 4; @@ -161,21 +162,30 @@ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto, struct tcphdr *th = (struct tcphdr *)(ip6h + 1); th->check = 0; - th->check = csum_ip4(ip6h, len + sizeof(*ip6h)); + th->check = csum_unaligned(ip6h, len + sizeof(*ip6h), + 0); } else if (proto == IPPROTO_UDP) { struct udphdr *uh = (struct udphdr *)(ip6h + 1); uh->check = 0; - uh->check = csum_ip4(ip6h, len + sizeof(*ip6h)); + uh->check = csum_unaligned(ip6h, len + sizeof(*ip6h), + 0); } else if (proto == IPPROTO_ICMPV6) { struct icmp6hdr *ih = (struct icmp6hdr *)(ip6h + 1); ih->icmp6_cksum = 0; - ih->icmp6_cksum = csum_ip4(ip6h, len + sizeof(*ip6h)); + ih->icmp6_cksum = csum_unaligned(ip6h, + len + sizeof(*ip6h), + 0); } ip6h->version = 6; ip6h->nexthdr = proto; ip6h->hop_limit = 255; + if (flow) { + ip6h->flow_lbl[0] = (flow >> 16) & 0xf; + ip6h->flow_lbl[1] = (flow >> 8) & 0xff; + ip6h->flow_lbl[2] = (flow >> 0) & 0xff; + } tap_send(c, buf, len + sizeof(*ip6h) + sizeof(*eh), 1); } diff --git a/tap.h b/tap.h index 385fab0..a87c121 100644 --- a/tap.h +++ b/tap.h @@ -1,5 +1,5 @@ void tap_ip_send(struct ctx *c, struct in6_addr *src, uint8_t proto, - char *in, size_t len); + char *in, size_t len, uint32_t flow); int tap_send(struct ctx *c, void *data, size_t len, int vnet_pre); void tap_handler(struct ctx *c, uint32_t events, struct timespec *now); void tap_sock_init(struct ctx *c); diff --git a/tcp.c b/tcp.c index ffcbeca..f783704 100644 --- a/tcp.c +++ b/tcp.c @@ -469,6 +469,7 @@ struct tcp_tap_conn { uint32_t seq_from_tap; uint32_t seq_ack_to_tap; uint32_t seq_init_from_tap; + uint32_t seq_init_to_tap; uint64_t tcpi_acked_last; int ws_allowed; @@ -934,7 +935,8 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn, memcpy(data, in, len); - tap_ip_send(c, &conn->a.a6, IPPROTO_TCP, buf, th->doff * 4 + len); + tap_ip_send(c, &conn->a.a6, IPPROTO_TCP, buf, th->doff * 4 + len, + conn->seq_init_to_tap); return 0; } @@ -1116,6 +1118,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr, conn->seq_ack_to_tap = conn->seq_from_tap; conn->seq_to_tap = tcp_seq_init(c, af, addr, th->dest, th->source, now); + conn->seq_init_to_tap = conn->seq_to_tap; conn->seq_ack_from_tap = conn->seq_to_tap + 1; tcp_hash_insert(c, conn, af, addr); @@ -1828,6 +1831,7 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref, conn->sock_port, conn->tap_port, now); + conn->seq_init_to_tap = conn->seq_to_tap; tcp_hash_insert(c, conn, AF_INET6, &sa6->sin6_addr); } else { @@ -1850,6 +1854,7 @@ static void tcp_conn_from_sock(struct ctx *c, union epoll_ref ref, conn->sock_port, conn->tap_port, now); + conn->seq_init_to_tap = conn->seq_to_tap; tcp_hash_insert(c, conn, AF_INET, &sa4->sin_addr); } -- cgit v1.2.3