aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2026-07-13 15:38:54 +1000
committerStefano Brivio <sbrivio@redhat.com>2026-07-15 01:22:47 +0200
commitaddd76dd9bc4306aa620bb0177d63368a24dc59d (patch)
tree27b7decf2404f2460b70df6eb618a37f0138e20c
parent66fdabd85c3eac3a87979f05484de2c90af9a272 (diff)
downloadpasst-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar.gz
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar.bz2
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar.lz
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar.xz
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.tar.zst
passt-addd76dd9bc4306aa620bb0177d63368a24dc59d.zip
fwd: Rework default address logic for inbound flows
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 <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--fwd.c41
-rw-r--r--inany.h2
2 files changed, 29 insertions, 14 deletions
diff --git a/fwd.c b/fwd.c
index 8440094..de444d9 100644
--- a/fwd.c
+++ b/fwd.c
@@ -1006,6 +1006,24 @@ bool nat_inbound(const struct ctx *c, const union inany_addr *addr,
}
/**
+ * 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
* @rule: Forwarding rule to apply
@@ -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 5b176cc..d0befb1 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