From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202606 header.b=H+JYJu+F; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id EFE105A061E for ; Mon, 13 Jul 2026 07:39:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202606; t=1783921140; bh=08cx+TBkFhWzxWjcBlucbGC/dN0ycbpr8lE0c+u/ZKc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H+JYJu+FqxdWom1J+rewHYzT8re0k8IAlhAukdwCIC6IMede/wmyg86wkEuCVe7FY wDSzBVpW+su2YjW36gxtUPRrq+iNAxYeRmYRgfwntggy3ru2BS3xNwJWykywNg/BMk y/ONE0dj5zRKD+51UwAiiaeWLwcEaio5DmgD/QfgBz9Zc2eNIpLPigXmHJ7IWjH0Wh Ao61Szym4G9YiqoJiFvrv3F5EaBb59xhaGw3xAq+PgVxizyAGKS3X+Sr+etQ2owZFs 4lIqjt6VtzUUGH+9z7xcw0r6zyXe6ViyvxUCRCEhX79szdhb9bNBduird6z4RUJkXt C6vrNpZQ32SyQ== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4gzB7m2d3Jz4wJS; Mon, 13 Jul 2026 15:39:00 +1000 (AEST) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v2 3/5] fwd: Rework default address logic for inbound flows Date: Mon, 13 Jul 2026 15:38:54 +1000 Message-ID: <20260713053856.1329271-4-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260713053856.1329271-1-david@gibson.dropbear.id.au> References: <20260713053856.1329271-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: LS5YWQMTPLST7UGGSPC3LTYDFHPKKHLU X-Message-ID-Hash: LS5YWQMTPLST7UGGSPC3LTYDFHPKKHLU 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: 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: fwd_nat_from_host() needs to determine the guest side destination address for the new flow. In some cases that's controlled by the forwarding rule or --host-lo-to-ns-lo logic, but by default we use the observed guest address. We need to pick the right one to match the source address, though. Currently this is done with similar, but not quite identical logic in the spliced and non-spliced paths. Introduce a new fwd_default_guest_addr() helper to make explicit: * We have the same logic for splice and tap paths * This is a fallback path if nothing else determined the address (we use this default nearly all the time now, but it might change in future) * We're matching IP family and scope with the guest side source address Signed-off-by: David Gibson --- fwd.c | 41 +++++++++++++++++++++++++++-------------- inany.h | 2 ++ 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/fwd.c b/fwd.c index 84400948..de444d9c 100644 --- a/fwd.c +++ b/fwd.c @@ -1005,6 +1005,24 @@ bool nat_inbound(const struct ctx *c, const union inany_addr *addr, return true; } +/** + * fwd_default_guest_addr() - Get appropriate guest address to send to + * @c: Execution context + * @template: Address to match IP version and scope of + * + * Return: the address of the guest, which best matches the IP version and scope + * of @template + */ +static union inany_addr fwd_default_guest_addr(const struct ctx *c, + const union inany_addr *template) +{ + if (inany_v4(template)) + return inany_from_v4(c->ip4.addr_seen); + if (inany_is_linklocal6(template)) + return inany_from_v6(c->ip6.addr_ll_seen); + return inany_from_v6(c->ip6.addr_seen); +} + /** * fwd_nat_from_host() - Determine to forward a flow from the host interface * @c: Execution context @@ -1040,13 +1058,9 @@ uint8_t fwd_nat_from_host(const struct ctx *c, */ if (c->host_lo_to_ns_lo && inany_is_loopback(&ini->oaddr)) tgt->eaddr = ini->oaddr; - else if (inany_v4(&ini->eaddr)) - tgt->eaddr = inany_from_v4(c->ip4.addr_seen); - else - tgt->eaddr.a6 = c->ip6.addr_seen; /* Let the kernel pick source address and port */ - if (inany_v4(&tgt->eaddr)) + if (inany_v4(&ini->eaddr)) tgt->oaddr = inany_any4; else tgt->oaddr = inany_any6; @@ -1056,6 +1070,9 @@ uint8_t fwd_nat_from_host(const struct ctx *c, /* But for UDP preserve the source port */ tgt->oport = ini->eport; + /* Use guest address as destination, if otherwise unspecified */ + if (inany_is_unspecified(&tgt->eaddr)) + tgt->eaddr = fwd_default_guest_addr(c, &tgt->oaddr); return PIF_SPLICE; } @@ -1074,16 +1091,12 @@ uint8_t fwd_nat_from_host(const struct ctx *c, } tgt->oport = ini->eport; - if (!inany_is_unspecified(&rule->taddr)) { + if (!inany_is_unspecified(&rule->taddr)) tgt->eaddr = rule->taddr; - } else if (inany_v4(&tgt->oaddr)) { - tgt->eaddr = inany_from_v4(c->ip4.addr_seen); - } else { - if (inany_is_linklocal6(&tgt->oaddr)) - tgt->eaddr.a6 = c->ip6.addr_ll_seen; - else - tgt->eaddr.a6 = c->ip6.addr_seen; - } + + /* Use guest address as destination, if otherwise unspecified */ + if (inany_is_unspecified(&tgt->eaddr)) + tgt->eaddr = fwd_default_guest_addr(c, &tgt->oaddr); return PIF_TAP; } diff --git a/inany.h b/inany.h index 5b176ccf..d0befb15 100644 --- a/inany.h +++ b/inany.h @@ -59,6 +59,8 @@ extern const union inany_addr inany_any4; #define inany_from_v4(a4) \ ((union inany_addr)INANY_INIT4((a4))) +#define inany_from_v6(a6_) \ + ((union inany_addr){.a6 = (a6_)}) /** union sockaddr_inany - Either a sockaddr_in or a sockaddr_in6 * @sa_family: Address family, AF_INET or AF_INET6 -- 2.55.0