From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id A1A635A005C for ; Fri, 14 Jun 2024 08:14:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202312; t=1718345632; bh=hq+4E0fL2z5R8rv/oP269LnivfbbJ5UnxKHnJZEYA34=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HpbVGI4ZT+4+jnmkdOF69WPn3mhpXzzf3vZhTJX1Z4ckZh2jOCjuC31s1bCdZf9sD HfPq85xsqRJLBlQ1nXLSdOXasT8EJZ6QFpnELx5jjS/LhPKQLx1v0q0tN67daa3Cm6 mI8Nvi2vjdlbvtEaxjF72bKyUJ/jy8Z2IjQHboQRdIO8CDQnXRx+HdqY22x6AWqwpv uNOSk4nIJWEmRbwb6jmBipCkDtxUIlVkQZCWOCcQxTOXQ9viuRdHJrv7V94OA6/g6W 0lpoCodc+VK5n0V+UGuXo0Yf3iwF5URmQPWxm0LB5ffgy52yz5XcfLdjHoWbGoy5OC +3zxZhuPm0m1A== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4W0prJ0Vt5z4wyY; Fri, 14 Jun 2024 16:13:52 +1000 (AEST) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v6 05/26] tcp: Manage outbound address via flow table Date: Fri, 14 Jun 2024 16:13:27 +1000 Message-ID: <20240614061348.3814736-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240614061348.3814736-1-david@gibson.dropbear.id.au> References: <20240614061348.3814736-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: NI4UWZL64ULKAMDERBMRVI5MNF6ZEJA5 X-Message-ID-Hash: NI4UWZL64ULKAMDERBMRVI5MNF6ZEJA5 X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: jmaloy@redhat.com, David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: For now when we forward a connection to the host we leave the host side forwarding address and port blank since we don't necessarily know what source address and port will be used by the kernel. When the outbound address option is active, though, we do know the address at least, so we can record it in the flowside. Having done that, use it as the primary source of truth, binding the outgoing socket based on the information in there. This allows the possibility of more complex rules for what outbound address and/or port we use in future. Signed-off-by: David Gibson --- tcp.c | 93 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/tcp.c b/tcp.c index df625751..74883312 100644 --- a/tcp.c +++ b/tcp.c @@ -1536,53 +1536,48 @@ static uint16_t tcp_conn_tap_mss(const struct tcp_tap_conn *conn, /** * tcp_bind_outbound() - Bind socket to outbound address and interface if given * @c: Execution context + * @conn: Connection entry for socket to bind * @s: Outbound TCP socket - * @af: Address family */ -static void tcp_bind_outbound(const struct ctx *c, int s, sa_family_t af) +static void tcp_bind_outbound(const struct ctx *c, + const struct tcp_tap_conn *conn, int s) { - if (af == AF_INET) { - if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr_out)) { - struct sockaddr_in addr4 = { - .sin_family = AF_INET, - .sin_port = 0, - .sin_addr = c->ip4.addr_out, - }; - - if (bind(s, (struct sockaddr *)&addr4, sizeof(addr4))) { - debug("Can't bind IPv4 TCP socket address: %s", - strerror(errno)); - } + const struct flowside *tgt = &conn->f.side[TGTSIDE]; + union sockaddr_inany bind_sa; + socklen_t sl; + + sockaddr_from_inany(&bind_sa, &sl, + &tgt->faddr, tgt->fport, c->ifi6); + + if (!inany_is_unspecified(&tgt->faddr) || tgt->fport) { + if (bind(s, &bind_sa.sa, sl)) { + char sstr[INANY_ADDRSTRLEN]; + + flow_dbg(conn, + "Can't bind TCP outbound socket to %s:%hu: %s", + inany_ntop(&tgt->faddr, sstr, sizeof(sstr)), + tgt->fport, strerror(errno)); } + } + if (bind_sa.sa_family == AF_INET) { if (*c->ip4.ifname_out) { if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, c->ip4.ifname_out, strlen(c->ip4.ifname_out))) { - debug("Can't bind IPv4 TCP socket to interface:" - " %s", strerror(errno)); - } - } - } else if (af == AF_INET6) { - if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_out)) { - struct sockaddr_in6 addr6 = { - .sin6_family = AF_INET6, - .sin6_port = 0, - .sin6_addr = c->ip6.addr_out, - }; - - if (bind(s, (struct sockaddr *)&addr6, sizeof(addr6))) { - debug("Can't bind IPv6 TCP socket address: %s", - strerror(errno)); + flow_dbg(conn, "Can't bind IPv4 TCP socket to" + " interface %s: %s", c->ip4.ifname_out, + strerror(errno)); } } - + } else if (bind_sa.sa_family == AF_INET6) { if (*c->ip6.ifname_out) { if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, c->ip6.ifname_out, strlen(c->ip6.ifname_out))) { - debug("Can't bind IPv6 TCP socket to interface:" - " %s", strerror(errno)); + flow_dbg(conn, "Can't bind IPv6 TCP socket to" + " interface %s: %s", c->ip6.ifname_out, + strerror(errno)); } } } @@ -1606,9 +1601,9 @@ static void tcp_conn_from_tap(struct ctx *c, sa_family_t af, { in_port_t srcport = ntohs(th->source); in_port_t dstport = ntohs(th->dest); + union inany_addr srcaddr, dstaddr; /* FIXME: Avoid bulky temporaries */ const struct flowside *ini, *tgt; struct tcp_tap_conn *conn; - union inany_addr dstaddr; /* FIXME: Avoid bulky temporary */ union sockaddr_inany sa; union flow *flow; int s = -1, mss; @@ -1666,23 +1661,27 @@ static void tcp_conn_from_tap(struct ctx *c, sa_family_t af, dstaddr = inany_loopback6; } + if (inany_is_linklocal6(&dstaddr)) { + srcaddr.a6 = c->ip6.addr_ll; + } else if (inany_is_loopback(&dstaddr)) { + srcaddr = dstaddr; + } else if (inany_v4(&dstaddr)) { + if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr_out)) + srcaddr = inany_from_v4(c->ip4.addr_out); + else + srcaddr = inany_any4; + } else { + if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_out)) + srcaddr.a6 = c->ip6.addr_out; + else + srcaddr = inany_any6; + } + /* FIXME: Record outbound source address when known */ tgt = flow_target_af(flow, PIF_HOST, AF_INET6, - NULL, 0, /* Kernel decides source address */ + &srcaddr, 0, /* Kernel decides source port */ &dstaddr, dstport); - if (inany_is_linklocal6(&tgt->eaddr)) { - struct sockaddr_in6 addr6_ll = { - .sin6_family = AF_INET6, - .sin6_addr = c->ip6.addr_ll, - .sin6_scope_id = c->ifi6, - }; - if (bind(s, (struct sockaddr *)&addr6_ll, sizeof(addr6_ll))) - goto cancel; - } else if (!inany_is_loopback(&tgt->eaddr)) { - tcp_bind_outbound(c, s, af); - } - conn = FLOW_SET_TYPE(flow, FLOW_TCP, tcp); conn->sock = s; conn->timer = -1; @@ -1721,6 +1720,8 @@ static void tcp_conn_from_tap(struct ctx *c, sa_family_t af, if (errno != EADDRNOTAVAIL && errno != EACCES) conn_flag(c, conn, LOCAL); + tcp_bind_outbound(c, conn, s); + if (connect(s, &sa.sa, sl)) { if (errno != EINPROGRESS) { tcp_rst(c, conn); -- 2.45.2