* [PATCH] tap: don't let overheard traffic move addr_seen when serving a fixed address
@ 2026-06-03 1:15 EJ Campbell
2026-06-05 11:57 ` Stefano Brivio
0 siblings, 1 reply; 3+ messages in thread
From: EJ Campbell @ 2026-06-03 1:15 UTC (permalink / raw)
To: passt-dev
The latest source address seen on the tap interface (ip4.addr_seen) is
taken to be the guest's and is used as the target for inbound port
forwarding. The update accepts any source address.
On a point-to-point tap that is always correct. But when the tap sits on
a shared L2 segment -- for example when it is bridged together with other
hosts -- pasta also sees frames from those other hosts. With a static
configuration (-a / address set, DHCP disabled), an overheard frame from
another host silently moves addr_seen to that host, and every subsequent
inbound forwarded connection is sent there instead of to the guest, so
connections are reset or hang.
I hit this running pasta with its tap enslaved to a Linux bridge that also
carries other traffic: inbound port forwarding to the guest broke as soon
as another address was seen on the segment.
Restrict the update so that, when DHCP is disabled (no_dhcp), only frames
sourced from the configured guest address may move addr_seen. With DHCP
enabled -- the default -- behaviour is unchanged, since the guest's
address is whatever pasta leases and tracking it is still correct.
The same reasoning applies to ip6.addr_seen on a shared segment; I left
IPv6 alone for now since I only exercise IPv4 in this setup, and would be
glad to extend it the same way if you prefer.
Signed-off-by: EJ Campbell <ej.campbell@gmail.com>
---
tap.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/tap.c b/tap.c
index 4cba4c7..514379e 100644
--- a/tap.c
+++ b/tap.c
@@ -770,7 +770,19 @@ resume:
continue;
}
- if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr)
+ /* The latest source address seen on the tap is taken to be the
+ * guest's, and becomes the target for inbound forwarding. On a
+ * point-to-point tap that's always correct. But if the tap sits
+ * on a shared L2 segment (for example bridged together with
+ * other hosts) and we serve a fixed address (DHCP disabled), a
+ * frame overheard from another host on that segment must not
+ * move addr_seen and silently retarget forwarded connections
+ * away from the guest. When DHCP is disabled, only the
+ * configured guest address may update addr_seen; with DHCP
+ * enabled (the default) behaviour is unchanged.
+ */
+ if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr &&
+ (!c->no_dhcp || iph->saddr == c->ip4.addr.s_addr))
c->ip4.addr_seen.s_addr = iph->saddr;
if (!iov_drop_header(&data, hlen))
base-commit: 4b2823784aab04a70dfc295b16fd6f0592955790
--
2.53.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] tap: don't let overheard traffic move addr_seen when serving a fixed address
2026-06-03 1:15 [PATCH] tap: don't let overheard traffic move addr_seen when serving a fixed address EJ Campbell
@ 2026-06-05 11:57 ` Stefano Brivio
2026-06-09 1:54 ` David Gibson
0 siblings, 1 reply; 3+ messages in thread
From: Stefano Brivio @ 2026-06-05 11:57 UTC (permalink / raw)
To: EJ Campbell; +Cc: ej, passt-dev, Jon Maloy, David Gibson
EJ, thanks for the detailed patch and commit message, and apologies for
the delayed response.
Some remarks:
On Tue, 2 Jun 2026 18:15:24 -0700
EJ Campbell <ej.campbell@gmail.com> wrote:
> The latest source address seen on the tap interface (ip4.addr_seen) is
> taken to be the guest's and is used as the target for inbound port
> forwarding. The update accepts any source address.
>
> On a point-to-point tap that is always correct. But when the tap sits on
> a shared L2 segment -- for example when it is bridged together with other
> hosts -- pasta also sees frames from those other hosts.
That's a interesting use case, it's the first time I see pasta used
like this. Thanks for sharing.
> With a static
> configuration (-a / address set, DHCP disabled), an overheard frame from
> another host silently moves addr_seen to that host, and every subsequent
> inbound forwarded connection is sent there instead of to the guest, so
> connections are reset or hang.
>
> I hit this running pasta with its tap enslaved to a Linux bridge that also
> carries other traffic: inbound port forwarding to the guest broke as soon
> as another address was seen on the segment.
Oops. We should definitely fix this, and maybe your patch is good enough
for the moment (or better than the alternative), but I have a concern
here:
> Restrict the update so that, when DHCP is disabled (no_dhcp), only frames
> sourced from the configured guest address may move addr_seen. With DHCP
> enabled -- the default -- behaviour is unchanged, since the guest's
> address is whatever pasta leases and tracking it is still correct.
...inferring possibly but not necessarily related information from
whether DHCP is disabled or enabled looks a bit risky to me:
- somebody might have DHCP enabled (just because it's the default
option), but one single connected container / guest not using DHCP at
all, and picking an address that we didn't expect. Your patch would
break this (perhaps unlikely?) usage
- somebody might have DHCP enabled but just the intended container /
guest using it, and your same problem. Your patch wouldn't fix that
(definitely less likely) usage
So I've been thinking: shouldn't we rather use as a condition the fact
that -a / --address was explicitly given? We don't track that from
conf() at the moment but it would be a small change.
If -a / --address is given, I'd say the user is very much expecting the
container / guest to be using that address, and in that case I think
it's safer to ignore other addresses.
It would be even better if we could track our designated container /
guest among a number of them, only if there are more than one.
For context, Jon is working on a series adding support for multiple
addresses (assigned, used, or observed):
https://archives.passt.top/passt-dev/20260413005319.3295910-1-jmaloy@redhat.com/
and patch 8/13:
https://archives.passt.top/passt-dev/20260413005319.3295910-9-jmaloy@redhat.com/
refactors the same exact part your patch is touching, here:
https://archives.passt.top/passt-dev/7f04e12/s/?b=tap.c#n764
with no functional change.
By the way, if you want to try things out on top of that series, you
can apply it with:
b4 shazam
https://archives.passt.top/passt-dev/20260413005319.3295910-1-jmaloy@redhat.com/
...you might want to check out a slightly older revision to apply
cleanly without conflicts.
The main purpose of this work is actually to implement a netlink
monitor to track changes in host addresses:
https://bugs.passt.top/show_bug.cgi?id=141
https://pad.passt.top/p/netlinkMonitor
...but it might also be convenient for this kind of tracking. For
guests, we could establish some preference rules, for example:
- if any guest made a DHCP / DHCPv6 request, select its address (I
guess we should eventually implement guest-side MAC address tracking
for a full solution but just preferring addresses we assigned might
be quite good). I'm not sure how we would handle SLAAC
- if we haven't seen any DHCP / DHCPv6 request, but we have seen a
single address, default to that one as "guest" address
and so on.
For containers, we actually know which namespace we're associated to,
so we could, on any new observed address, check the source MAC address
of the frame and see if it corresponds to our namespace (querying via
netlink).
Thoughts? Jon?
If this is all too complicated for the moment, would a condition based
on explicit -a / --address option work for you?
> The same reasoning applies to ip6.addr_seen on a shared segment; I left
> IPv6 alone for now since I only exercise IPv4 in this setup, and would be
> glad to extend it the same way if you prefer.
I think we should definitely take care of IPv6 as well, I'm just not
sure how.
A couple of comments about the patch itself:
> Signed-off-by: EJ Campbell <ej.campbell@gmail.com>
> ---
> tap.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/tap.c b/tap.c
> index 4cba4c7..514379e 100644
> --- a/tap.c
> +++ b/tap.c
> @@ -770,7 +770,19 @@ resume:
> continue;
It looks like the patch itself was copied and pasted from a terminal,
because all tabs became spaces, and the patch doesn't apply.
It's not a problem for small patches like this one as I tend to fix
things up manually, but it would be good to have it directly from git
send-email instead.
> }
>
> - if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr)
> + /* The latest source address seen on the tap is taken to be the
> + * guest's, and becomes the target for inbound forwarding. On a
> + * point-to-point tap that's always correct. But if the tap sits
> + * on a shared L2 segment (for example bridged together with
> + * other hosts) and we serve a fixed address (DHCP disabled), a
> + * frame overheard from another host on that segment must not
> + * move addr_seen and silently retarget forwarded connections
> + * away from the guest. When DHCP is disabled, only the
> + * configured guest address may update addr_seen; with DHCP
> + * enabled (the default) behaviour is unchanged.
The fact that the behaviour is _unchanged_ (by your patch) belongs in
the commit message rather than the code, because if one reads the code
they aren't explicitly reading your change and it's not clear to what
previous behaviour you would be referring to.
Other than that it's pretty well described, thanks. Let's see if we can
find a better solution though.
> + */
> + if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr &&
> + (!c->no_dhcp || iph->saddr == c->ip4.addr.s_addr))
> c->ip4.addr_seen.s_addr = iph->saddr;
>
> if (!iov_drop_header(&data, hlen))
>
> base-commit: 4b2823784aab04a70dfc295b16fd6f0592955790
> --
> 2.53.0
>
--
Stefano
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] tap: don't let overheard traffic move addr_seen when serving a fixed address
2026-06-05 11:57 ` Stefano Brivio
@ 2026-06-09 1:54 ` David Gibson
0 siblings, 0 replies; 3+ messages in thread
From: David Gibson @ 2026-06-09 1:54 UTC (permalink / raw)
To: Stefano Brivio; +Cc: EJ Campbell, ej, passt-dev, Jon Maloy
[-- Attachment #1: Type: text/plain, Size: 9660 bytes --]
On Fri, Jun 05, 2026 at 01:57:41PM +0200, Stefano Brivio wrote:
> EJ, thanks for the detailed patch and commit message, and apologies for
> the delayed response.
>
> Some remarks:
>
> On Tue, 2 Jun 2026 18:15:24 -0700
> EJ Campbell <ej.campbell@gmail.com> wrote:
>
> > The latest source address seen on the tap interface (ip4.addr_seen) is
> > taken to be the guest's and is used as the target for inbound port
> > forwarding. The update accepts any source address.
> >
> > On a point-to-point tap that is always correct. But when the tap sits on
> > a shared L2 segment -- for example when it is bridged together with other
> > hosts -- pasta also sees frames from those other hosts.
>
> That's a interesting use case, it's the first time I see pasta used
> like this. Thanks for sharing.
Likewise, it's the first I've heard of someone using it specifically
like this, but it is a use model I've had in mind for a while. So
this is a known limitation I've been thinking about for a while. It
hasn't reached the top of my priority list because while your very
specific case almost works already, the more general case of a bridge
on the guest side requires a bunch more infrastructure. That's in
progress or at least planned, but it's going to be a while.
Fwiw, I really dislike the addr_seen mechanism even in cases where it
"works": it allows poorly configured guests to work at the expense of
substantial complexity which impacts all cases. However, it's
established behaviour, so Stefano is understandably against simply
removing it.
> > With a static
> > configuration (-a / address set, DHCP disabled), an overheard frame from
> > another host silently moves addr_seen to that host, and every subsequent
> > inbound forwarded connection is sent there instead of to the guest, so
> > connections are reset or hang.
> >
> > I hit this running pasta with its tap enslaved to a Linux bridge that also
> > carries other traffic: inbound port forwarding to the guest broke as soon
> > as another address was seen on the segment.
>
> Oops. We should definitely fix this, and maybe your patch is good enough
> for the moment (or better than the alternative), but I have a concern
> here:
>
> > Restrict the update so that, when DHCP is disabled (no_dhcp), only frames
> > sourced from the configured guest address may move addr_seen. With DHCP
> > enabled -- the default -- behaviour is unchanged, since the guest's
> > address is whatever pasta leases and tracking it is still correct.
>
> ...inferring possibly but not necessarily related information from
> whether DHCP is disabled or enabled looks a bit risky to me:
>
> - somebody might have DHCP enabled (just because it's the default
> option), but one single connected container / guest not using DHCP at
> all, and picking an address that we didn't expect. Your patch would
> break this (perhaps unlikely?) usage
>
> - somebody might have DHCP enabled but just the intended container /
> guest using it, and your same problem. Your patch wouldn't fix that
> (definitely less likely) usage
Right. I agree with Stefano that basing this of --no-dhcp is not a
good idea. It happens to work for your case, but it doesn't
generalise well. In addition to the cases Stefano mentions, for the
more general case of a guest-side bridge, we'd eventually like to have
our DHCP implementation serve multiple address, in which case we
wouldn't want addr_seen, even though DHCP is enabled.
> So I've been thinking: shouldn't we rather use as a condition the fact
> that -a / --address was explicitly given? We don't track that from
> conf() at the moment but it would be a small change.
>
> If -a / --address is given, I'd say the user is very much expecting the
> container / guest to be using that address, and in that case I think
> it's safer to ignore other addresses.
I think having an explcit -a is a sufficient condition to disable
addr_seen, but maybe not a necessary one. I think requiring the guest
to use the assigned address would be a reasonable request, even if
that address is taken from the host.
Stefano and others talked me out of an explicit --no-address-snooping
option, on the grounds of option proliferation at our last call.
However, thinking about it again, I'm still wondering if it might be
useful: we can think of addr_seen as a (not very good) address
assignment mechanism, along with DHCP, NDP, DHCPv6 and --config-net.
All of those (better) mechanisms can be explicitly disabled, so why
should we not be able to disable the worst one.
> It would be even better if we could track our designated container /
> guest among a number of them, only if there are more than one.
>
> For context, Jon is working on a series adding support for multiple
> addresses (assigned, used, or observed):
>
> https://archives.passt.top/passt-dev/20260413005319.3295910-1-jmaloy@redhat.com/
>
> and patch 8/13:
>
> https://archives.passt.top/passt-dev/20260413005319.3295910-9-jmaloy@redhat.com/
>
> refactors the same exact part your patch is touching, here:
>
> https://archives.passt.top/passt-dev/7f04e12/s/?b=tap.c#n764
>
> with no functional change.
>
> By the way, if you want to try things out on top of that series, you
> can apply it with:
>
> b4 shazam
> https://archives.passt.top/passt-dev/20260413005319.3295910-1-jmaloy@redhat.com/
>
> ...you might want to check out a slightly older revision to apply
> cleanly without conflicts.
>
> The main purpose of this work is actually to implement a netlink
> monitor to track changes in host addresses:
>
> https://bugs.passt.top/show_bug.cgi?id=141
> https://pad.passt.top/p/netlinkMonitor
>
> ...but it might also be convenient for this kind of tracking. For
> guests, we could establish some preference rules, for example:
>
> - if any guest made a DHCP / DHCPv6 request, select its address (I
> guess we should eventually implement guest-side MAC address tracking
> for a full solution but just preferring addresses we assigned might
> be quite good). I'm not sure how we would handle SLAAC
>
> - if we haven't seen any DHCP / DHCPv6 request, but we have seen a
> single address, default to that one as "guest" address
>
> and so on.
>
> For containers, we actually know which namespace we're associated to,
> so we could, on any new observed address, check the source MAC address
> of the frame and see if it corresponds to our namespace (querying via
> netlink).
>
> Thoughts? Jon?
>
> If this is all too complicated for the moment, would a condition based
> on explicit -a / --address option work for you?
>
> > The same reasoning applies to ip6.addr_seen on a shared segment; I left
> > IPv6 alone for now since I only exercise IPv4 in this setup, and would be
> > glad to extend it the same way if you prefer.
>
> I think we should definitely take care of IPv6 as well, I'm just not
> sure how.
>
> A couple of comments about the patch itself:
>
> > Signed-off-by: EJ Campbell <ej.campbell@gmail.com>
> > ---
> > tap.c | 14 +++++++++++++-
> > 1 file changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/tap.c b/tap.c
> > index 4cba4c7..514379e 100644
> > --- a/tap.c
> > +++ b/tap.c
> > @@ -770,7 +770,19 @@ resume:
> > continue;
>
> It looks like the patch itself was copied and pasted from a terminal,
> because all tabs became spaces, and the patch doesn't apply.
>
> It's not a problem for small patches like this one as I tend to fix
> things up manually, but it would be good to have it directly from git
> send-email instead.
>
> > }
> >
> > - if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr)
> > + /* The latest source address seen on the tap is taken to be the
> > + * guest's, and becomes the target for inbound forwarding. On a
> > + * point-to-point tap that's always correct. But if the tap sits
> > + * on a shared L2 segment (for example bridged together with
> > + * other hosts) and we serve a fixed address (DHCP disabled), a
> > + * frame overheard from another host on that segment must not
> > + * move addr_seen and silently retarget forwarded connections
> > + * away from the guest. When DHCP is disabled, only the
> > + * configured guest address may update addr_seen; with DHCP
> > + * enabled (the default) behaviour is unchanged.
>
> The fact that the behaviour is _unchanged_ (by your patch) belongs in
> the commit message rather than the code, because if one reads the code
> they aren't explicitly reading your change and it's not clear to what
> previous behaviour you would be referring to.
>
> Other than that it's pretty well described, thanks. Let's see if we can
> find a better solution though.
>
> > + */
> > + if (iph->saddr && c->ip4.addr_seen.s_addr != iph->saddr &&
> > + (!c->no_dhcp || iph->saddr == c->ip4.addr.s_addr))
> > c->ip4.addr_seen.s_addr = iph->saddr;
> >
> > if (!iov_drop_header(&data, hlen))
> >
> > base-commit: 4b2823784aab04a70dfc295b16fd6f0592955790
> > --
> > 2.53.0
> >
>
> --
> Stefano
>
>
--
David Gibson (he or they) | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you, not the other way
| around.
http://www.ozlabs.org/~dgibson
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-09 1:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-03 1:15 [PATCH] tap: don't let overheard traffic move addr_seen when serving a fixed address EJ Campbell
2026-06-05 11:57 ` Stefano Brivio
2026-06-09 1:54 ` David Gibson
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).