tcp: Obtain guest address from flowside

Currently we always deliver inbound TCP packets to the guest's most
recent observed IP address.  This has the odd side effect that if the
guest changes its IP address with active TCP connections we might
deliver packets from old connections to the new address.  That won't
work; it will probably result in an RST from the guest.  Worse, if the
guest added a new address but also retains the old one, then we could
break those old connections by redirecting them to the new address.

Now that we maintain flowside information, we have a record of the correct
guest side address and can just use it.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
This commit is contained in:
David Gibson 2024-07-18 15:26:30 +10:00 committed by Stefano Brivio
parent f9fe212b1f
commit 52d45f1737
3 changed files with 17 additions and 33 deletions

41
tcp.c
View file

@ -1059,7 +1059,6 @@ static void tcp_fill_header(struct tcphdr *th,
/** /**
* tcp_fill_headers4() - Fill 802.3, IPv4, TCP headers in pre-cooked buffers * tcp_fill_headers4() - Fill 802.3, IPv4, TCP headers in pre-cooked buffers
* @c: Execution context
* @conn: Connection pointer * @conn: Connection pointer
* @taph: tap backend specific header * @taph: tap backend specific header
* @iph: Pointer to IPv4 header * @iph: Pointer to IPv4 header
@ -1070,27 +1069,26 @@ static void tcp_fill_header(struct tcphdr *th,
* *
* Return: The IPv4 payload length, host order * Return: The IPv4 payload length, host order
*/ */
static size_t tcp_fill_headers4(const struct ctx *c, static size_t tcp_fill_headers4(const struct tcp_tap_conn *conn,
const struct tcp_tap_conn *conn,
struct tap_hdr *taph, struct tap_hdr *taph,
struct iphdr *iph, struct tcphdr *th, struct iphdr *iph, struct tcphdr *th,
size_t dlen, const uint16_t *check, size_t dlen, const uint16_t *check,
uint32_t seq) uint32_t seq)
{ {
const struct flowside *tapside = TAPFLOW(conn); const struct flowside *tapside = TAPFLOW(conn);
const struct in_addr *a4 = inany_v4(&tapside->faddr); const struct in_addr *src4 = inany_v4(&tapside->faddr);
const struct in_addr *dst4 = inany_v4(&tapside->eaddr);
size_t l4len = dlen + sizeof(*th); size_t l4len = dlen + sizeof(*th);
size_t l3len = l4len + sizeof(*iph); size_t l3len = l4len + sizeof(*iph);
ASSERT(a4); ASSERT(src4 && dst4);
iph->tot_len = htons(l3len); iph->tot_len = htons(l3len);
iph->saddr = a4->s_addr; iph->saddr = src4->s_addr;
iph->daddr = c->ip4.addr_seen.s_addr; iph->daddr = dst4->s_addr;
iph->check = check ? *check : iph->check = check ? *check :
csum_ip4_header(l3len, IPPROTO_TCP, csum_ip4_header(l3len, IPPROTO_TCP, *src4, *dst4);
*a4, c->ip4.addr_seen);
tcp_fill_header(th, conn, seq); tcp_fill_header(th, conn, seq);
@ -1103,7 +1101,6 @@ static size_t tcp_fill_headers4(const struct ctx *c,
/** /**
* tcp_fill_headers6() - Fill 802.3, IPv6, TCP headers in pre-cooked buffers * tcp_fill_headers6() - Fill 802.3, IPv6, TCP headers in pre-cooked buffers
* @c: Execution context
* @conn: Connection pointer * @conn: Connection pointer
* @taph: tap backend specific header * @taph: tap backend specific header
* @ip6h: Pointer to IPv6 header * @ip6h: Pointer to IPv6 header
@ -1114,8 +1111,7 @@ static size_t tcp_fill_headers4(const struct ctx *c,
* *
* Return: The IPv6 payload length, host order * Return: The IPv6 payload length, host order
*/ */
static size_t tcp_fill_headers6(const struct ctx *c, static size_t tcp_fill_headers6(const struct tcp_tap_conn *conn,
const struct tcp_tap_conn *conn,
struct tap_hdr *taph, struct tap_hdr *taph,
struct ipv6hdr *ip6h, struct tcphdr *th, struct ipv6hdr *ip6h, struct tcphdr *th,
size_t dlen, uint32_t seq) size_t dlen, uint32_t seq)
@ -1125,10 +1121,7 @@ static size_t tcp_fill_headers6(const struct ctx *c,
ip6h->payload_len = htons(l4len); ip6h->payload_len = htons(l4len);
ip6h->saddr = tapside->faddr.a6; ip6h->saddr = tapside->faddr.a6;
if (IN6_IS_ADDR_LINKLOCAL(&ip6h->saddr)) ip6h->daddr = tapside->eaddr.a6;
ip6h->daddr = c->ip6.addr_ll_seen;
else
ip6h->daddr = c->ip6.addr_seen;
ip6h->hop_limit = 255; ip6h->hop_limit = 255;
ip6h->version = 6; ip6h->version = 6;
@ -1149,7 +1142,6 @@ static size_t tcp_fill_headers6(const struct ctx *c,
/** /**
* tcp_l2_buf_fill_headers() - Fill 802.3, IP, TCP headers in pre-cooked buffers * tcp_l2_buf_fill_headers() - Fill 802.3, IP, TCP headers in pre-cooked buffers
* @c: Execution context
* @conn: Connection pointer * @conn: Connection pointer
* @iov: Pointer to an array of iovec of TCP pre-cooked buffers * @iov: Pointer to an array of iovec of TCP pre-cooked buffers
* @dlen: TCP payload length * @dlen: TCP payload length
@ -1158,8 +1150,7 @@ static size_t tcp_fill_headers6(const struct ctx *c,
* *
* Return: IP payload length, host order * Return: IP payload length, host order
*/ */
size_t tcp_l2_buf_fill_headers(const struct ctx *c, size_t tcp_l2_buf_fill_headers(const struct tcp_tap_conn *conn,
const struct tcp_tap_conn *conn,
struct iovec *iov, size_t dlen, struct iovec *iov, size_t dlen,
const uint16_t *check, uint32_t seq) const uint16_t *check, uint32_t seq)
{ {
@ -1167,13 +1158,13 @@ size_t tcp_l2_buf_fill_headers(const struct ctx *c,
const struct in_addr *a4 = inany_v4(&tapside->faddr); const struct in_addr *a4 = inany_v4(&tapside->faddr);
if (a4) { if (a4) {
return tcp_fill_headers4(c, conn, iov[TCP_IOV_TAP].iov_base, return tcp_fill_headers4(conn, iov[TCP_IOV_TAP].iov_base,
iov[TCP_IOV_IP].iov_base, iov[TCP_IOV_IP].iov_base,
iov[TCP_IOV_PAYLOAD].iov_base, dlen, iov[TCP_IOV_PAYLOAD].iov_base, dlen,
check, seq); check, seq);
} }
return tcp_fill_headers6(c, conn, iov[TCP_IOV_TAP].iov_base, return tcp_fill_headers6(conn, iov[TCP_IOV_TAP].iov_base,
iov[TCP_IOV_IP].iov_base, iov[TCP_IOV_IP].iov_base,
iov[TCP_IOV_PAYLOAD].iov_base, dlen, iov[TCP_IOV_PAYLOAD].iov_base, dlen,
seq); seq);
@ -1476,17 +1467,11 @@ static void tcp_seq_init(const struct ctx *c, struct tcp_tap_conn *conn,
{ {
struct siphash_state state = SIPHASH_INIT(c->hash_secret); struct siphash_state state = SIPHASH_INIT(c->hash_secret);
const struct flowside *tapside = TAPFLOW(conn); const struct flowside *tapside = TAPFLOW(conn);
union inany_addr aany;
uint64_t hash; uint64_t hash;
uint32_t ns; uint32_t ns;
if (CONN_V4(conn))
inany_from_af(&aany, AF_INET, &c->ip4.addr);
else
inany_from_af(&aany, AF_INET6, &c->ip6.addr);
inany_siphash_feed(&state, &tapside->faddr); inany_siphash_feed(&state, &tapside->faddr);
inany_siphash_feed(&state, &aany); inany_siphash_feed(&state, &tapside->eaddr);
hash = siphash_final(&state, 36, hash = siphash_final(&state, 36,
(uint64_t)tapside->fport << 16 | tapside->eport); (uint64_t)tapside->fport << 16 | tapside->eport);

View file

@ -316,7 +316,7 @@ int tcp_buf_send_flag(struct ctx *c, struct tcp_tap_conn *conn, int flags)
return ret; return ret;
} }
l4len = tcp_l2_buf_fill_headers(c, conn, iov, optlen, NULL, seq); l4len = tcp_l2_buf_fill_headers(conn, iov, optlen, NULL, seq);
iov[TCP_IOV_PAYLOAD].iov_len = l4len; iov[TCP_IOV_PAYLOAD].iov_len = l4len;
if (flags & DUP_ACK) { if (flags & DUP_ACK) {
@ -373,7 +373,7 @@ static void tcp_data_to_tap(const struct ctx *c, struct tcp_tap_conn *conn,
tcp4_frame_conns[tcp4_payload_used] = conn; tcp4_frame_conns[tcp4_payload_used] = conn;
iov = tcp4_l2_iov[tcp4_payload_used++]; iov = tcp4_l2_iov[tcp4_payload_used++];
l4len = tcp_l2_buf_fill_headers(c, conn, iov, dlen, check, seq); l4len = tcp_l2_buf_fill_headers(conn, iov, dlen, check, seq);
iov[TCP_IOV_PAYLOAD].iov_len = l4len; iov[TCP_IOV_PAYLOAD].iov_len = l4len;
if (tcp4_payload_used > TCP_FRAMES_MEM - 1) if (tcp4_payload_used > TCP_FRAMES_MEM - 1)
tcp_payload_flush(c); tcp_payload_flush(c);
@ -381,7 +381,7 @@ static void tcp_data_to_tap(const struct ctx *c, struct tcp_tap_conn *conn,
tcp6_frame_conns[tcp6_payload_used] = conn; tcp6_frame_conns[tcp6_payload_used] = conn;
iov = tcp6_l2_iov[tcp6_payload_used++]; iov = tcp6_l2_iov[tcp6_payload_used++];
l4len = tcp_l2_buf_fill_headers(c, conn, iov, dlen, NULL, seq); l4len = tcp_l2_buf_fill_headers(conn, iov, dlen, NULL, seq);
iov[TCP_IOV_PAYLOAD].iov_len = l4len; iov[TCP_IOV_PAYLOAD].iov_len = l4len;
if (tcp6_payload_used > TCP_FRAMES_MEM - 1) if (tcp6_payload_used > TCP_FRAMES_MEM - 1)
tcp_payload_flush(c); tcp_payload_flush(c);

View file

@ -88,8 +88,7 @@ void tcp_rst_do(struct ctx *c, struct tcp_tap_conn *conn);
tcp_rst_do(c, conn); \ tcp_rst_do(c, conn); \
} while (0) } while (0)
size_t tcp_l2_buf_fill_headers(const struct ctx *c, size_t tcp_l2_buf_fill_headers(const struct tcp_tap_conn *conn,
const struct tcp_tap_conn *conn,
struct iovec *iov, size_t dlen, struct iovec *iov, size_t dlen,
const uint16_t *check, uint32_t seq); const uint16_t *check, uint32_t seq);
int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn, int tcp_update_seqack_wnd(const struct ctx *c, struct tcp_tap_conn *conn,