<feed xmlns='http://www.w3.org/2005/Atom'>
<title>passt, branch bug209</title>
<subtitle>Plug A Simple Socket Transport</subtitle>
<link rel='alternate' type='text/html' href='https://passt.top/passt/'/>
<entry>
<title>fwd: Don't rewrite inbound multicast destinations</title>
<updated>2026-07-10T05:50:35+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-10T05:38:42+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=e5932b92fded86b8077d0b5a737e5477bb0c946d'/>
<id>e5932b92fded86b8077d0b5a737e5477bb0c946d</id>
<content type='text'>
fwd_nat_from_host() (nearly) always rewrites the destination address for
inbound flows to the observed guest address.  Usually, that makes sense:
regardless of the host address to which the new flow arrived, we want to
direct it to the guest.  However, that clearly does not make sense for
multicast - it should still appear as a multicast transmission to the
guest.

In particular this can work very badly for multicast protocols which use
the same source and destination ports by convention (e.g. mDNS).  In this
case, we will attempt to forword multicast packets to our own socket,
causing a forwarding loop (see bug 209 for more details).

While it's certainly not enough to make us handle multicast correctly in
all circumstances, not translating multicast destinations is closer to
correct, and prevents bug 209 at least.

Link: https://bugs.passt.top/show_bug.cgi?id=209
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
fwd_nat_from_host() (nearly) always rewrites the destination address for
inbound flows to the observed guest address.  Usually, that makes sense:
regardless of the host address to which the new flow arrived, we want to
direct it to the guest.  However, that clearly does not make sense for
multicast - it should still appear as a multicast transmission to the
guest.

In particular this can work very badly for multicast protocols which use
the same source and destination ports by convention (e.g. mDNS).  In this
case, we will attempt to forword multicast packets to our own socket,
causing a forwarding loop (see bug 209 for more details).

While it's certainly not enough to make us handle multicast correctly in
all circumstances, not translating multicast destinations is closer to
correct, and prevents bug 209 at least.

Link: https://bugs.passt.top/show_bug.cgi?id=209
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd: Reorder DNAPT and SNAT steps in fwd_nat_from_host()</title>
<updated>2026-07-10T05:26:51+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-10T05:26:51+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=2ef86a35c5f9e2c518329a64162ecee7838f190a'/>
<id>2ef86a35c5f9e2c518329a64162ecee7838f190a</id>
<content type='text'>
The order in which we translate source and destination addresses is a bit
unclear in fwd_nat_from_host().  Reorder things to make it clearer:
   1. Pick guest-side destination address, where options require it
   2. Pick guest-side source address (needs to be different for SPLICE and
      TAP)
   3. If (1) didn't determine destination, pick a fallback to match family
      and scope of source address from (2).

As a small bonus this lets us make step (1) common between SPLICE and TAP
paths.  The value of this is a bit dubious right now, but it will make some
future changes clearer.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The order in which we translate source and destination addresses is a bit
unclear in fwd_nat_from_host().  Reorder things to make it clearer:
   1. Pick guest-side destination address, where options require it
   2. Pick guest-side source address (needs to be different for SPLICE and
      TAP)
   3. If (1) didn't determine destination, pick a fallback to match family
      and scope of source address from (2).

As a small bonus this lets us make step (1) common between SPLICE and TAP
paths.  The value of this is a bit dubious right now, but it will make some
future changes clearer.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd: Rework default address logic for inbound flows</title>
<updated>2026-07-10T05:19:29+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-10T05:13:57+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=058d9cfed9289654fa0be94b09d8d0bfd13648b7'/>
<id>058d9cfed9289654fa0be94b09d8d0bfd13648b7</id>
<content type='text'>
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 &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>udp: Validate that we have a unicast source address</title>
<updated>2026-07-09T01:02:34+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-07T04:00:25+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=ee3090686b9184321913e351a036f17ba3a79648'/>
<id>ee3090686b9184321913e351a036f17ba3a79648</id>
<content type='text'>
When creating a UDP flow from a socket we, correctly, check that the source
address is unicast - multicast addresses are not valid as a source address.
However, when creating a flow from tap we only check the source address
is specified, not that it is unicast.  Correct this.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
When creating a UDP flow from a socket we, correctly, check that the source
address is unicast - multicast addresses are not valid as a source address.
However, when creating a flow from tap we only check the source address
is specified, not that it is unicast.  Correct this.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd: Clarify semantics of --host-lo-to-ns-lo</title>
<updated>2026-07-09T01:02:34+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-06-30T04:09:47+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=0d91b54eaf2ba12e584e6be985804b153cd792f6'/>
<id>0d91b54eaf2ba12e584e6be985804b153cd792f6</id>
<content type='text'>
The semantics of --host-lo-to-ns-lo as described in the man page don't
quite make sense: It says without the option forwarded packets will appear
to come _from_ the guest's public address, which is not usually true.
Instead the packets will arrive *to* the guest's public address.  The exact
semantics are also a bit confusing in general.

Rewrite both the man page and code to clarify this.  The new rule is that
it redirects connections addressed to a host loopback address to the same
loopback address in the guest.  This is notionally different from what we
had in two ways:
  * We can now deliver to nonstandard loopback addresses within the guest,
    not just the default one.  This is technically a behavioural change,
    but I think will be less surprising behaviour.
  * The decision is now made on the original _destination_ address, rather
    than source address.  That's different theoreically, but not in
    practice, since loopback packets must have loopback addresses for both
    source and destination.

We make it explicitly incompatible with --no-splice - previously it
was allowed, but would have no effect in that case.

As well as being more precise right now, these semantics will intersect
better with upcoming remapping of target address by forwarding rules.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The semantics of --host-lo-to-ns-lo as described in the man page don't
quite make sense: It says without the option forwarded packets will appear
to come _from_ the guest's public address, which is not usually true.
Instead the packets will arrive *to* the guest's public address.  The exact
semantics are also a bit confusing in general.

Rewrite both the man page and code to clarify this.  The new rule is that
it redirects connections addressed to a host loopback address to the same
loopback address in the guest.  This is notionally different from what we
had in two ways:
  * We can now deliver to nonstandard loopback addresses within the guest,
    not just the default one.  This is technically a behavioural change,
    but I think will be less surprising behaviour.
  * The decision is now made on the original _destination_ address, rather
    than source address.  That's different theoreically, but not in
    practice, since loopback packets must have loopback addresses for both
    source and destination.

We make it explicitly incompatible with --no-splice - previously it
was allowed, but would have no effect in that case.

As well as being more precise right now, these semantics will intersect
better with upcoming remapping of target address by forwarding rules.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>isolation: Add --chroot-fallback option</title>
<updated>2026-07-08T19:41:33+00:00</updated>
<author>
<name>Mateusz Andrzejewski</name>
<email>mandrzejewski06@gmail.com</email>
</author>
<published>2026-07-02T07:13:31+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=6ef3d1c86ffc690a17a9a4445df4a741446bcd44'/>
<id>6ef3d1c86ffc690a17a9a4445df4a741446bcd44</id>
<content type='text'>
For integrations, which use rootfs on tmpfs or initramfs, it is not
allowed to use pivot_root(). It results with invalid argument (EINVAL)
error. Introduce --chroot-fallback option as a workaround with
MS_MOVE + chroot().

Due to weaker isolation of chroot() method (we don't unmount old root),
user has tu explicitly enable fallback with the new option. First,
always try to sandbox with pivot_root(). In both cases the new root is
placed into an empty tmpfs.

For the solution to work we keep CAP_SYS_CHROOT capability, which is
dropped at the end of the isolate_prefork() function.

Link: https://bugs.passt.top/show_bug.cgi?id=104
Signed-off-by: Mateusz Andrzejewski &lt;mateusz.andrzejewski@mikronika.com.pl&gt;
[sbrivio: Minor tweaks to comments, usage, man page]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
For integrations, which use rootfs on tmpfs or initramfs, it is not
allowed to use pivot_root(). It results with invalid argument (EINVAL)
error. Introduce --chroot-fallback option as a workaround with
MS_MOVE + chroot().

Due to weaker isolation of chroot() method (we don't unmount old root),
user has tu explicitly enable fallback with the new option. First,
always try to sandbox with pivot_root(). In both cases the new root is
placed into an empty tmpfs.

For the solution to work we keep CAP_SYS_CHROOT capability, which is
dropped at the end of the isolate_prefork() function.

Link: https://bugs.passt.top/show_bug.cgi?id=104
Signed-off-by: Mateusz Andrzejewski &lt;mateusz.andrzejewski@mikronika.com.pl&gt;
[sbrivio: Minor tweaks to comments, usage, man page]
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd, fwd_rule: Implement configurable target address mapping</title>
<updated>2026-07-08T18:59:11+00:00</updated>
<author>
<name>Stefano Brivio</name>
<email>sbrivio@redhat.com</email>
</author>
<published>2026-07-07T04:24:52+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=e67acdebc2b725a9b4f80eaec17ff0d9771229fc'/>
<id>e67acdebc2b725a9b4f80eaec17ff0d9771229fc</id>
<content type='text'>
Add a 'taddr' field to forwarding rules, which controls the destination
address on the target side.  Since changing the structure alters the pesto
update protocol, bump the protocol version number

[dwg: Split from option parsing code, added protocol version bump,
 explicitly exclude splicing with target address for now]
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Add a 'taddr' field to forwarding rules, which controls the destination
address on the target side.  Since changing the structure alters the pesto
update protocol, bump the protocol version number

[dwg: Split from option parsing code, added protocol version bump,
 explicitly exclude splicing with target address for now]
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd_rule: Parse target addresses for forwarding rules</title>
<updated>2026-07-08T18:58:59+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-07T04:24:51+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=c8145c3bb2cca31599eeb483e7c8e5d428c72b4b'/>
<id>c8145c3bb2cca31599eeb483e7c8e5d428c72b4b</id>
<content type='text'>
Extend the parsing of forwarding rules (-[tu]) to allow the destination
address on the target side to be specified.  For now just parse them, and
give an error if we try to create rules with a specified target address.
We'll implement the actual forwarding logic in another patch.

Format (for either command line or pesto):
      -t 2222:192.0.2.1/2222

This should work along with all the other bits, that is, say:
      -t 192.0.2.1%eth0/2222-2225:192.0.2.2/22-25

FIXME: Ban for -[TU] for now
FIXME: Check interaction with splice handling

[dwg: Syntax from Stefano's earlier draft, largely rewritten on top of new
 parsing helpers]
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Extend the parsing of forwarding rules (-[tu]) to allow the destination
address on the target side to be specified.  For now just parse them, and
give an error if we try to create rules with a specified target address.
We'll implement the actual forwarding logic in another patch.

Format (for either command line or pesto):
      -t 2222:192.0.2.1/2222

This should work along with all the other bits, that is, say:
      -t 192.0.2.1%eth0/2222-2225:192.0.2.2/22-25

FIXME: Ban for -[TU] for now
FIXME: Check interaction with splice handling

[dwg: Syntax from Stefano's earlier draft, largely rewritten on top of new
 parsing helpers]
Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd_rule: Rewrite forward rule parsing using parse.c helpers</title>
<updated>2026-07-04T11:14:32+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-03T03:54:45+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=bf2103815db917e532cad0b9b3530604de463d5a'/>
<id>bf2103815db917e532cad0b9b3530604de463d5a</id>
<content type='text'>
Forwarding rules for the -[tTuU] options are parsed in fwd_rule_parse()
and fwd_rule_parse_ports().  Currently those use a mix of loosely
recursive descent parsing helpers, consuming input from left to right,
and ad-hoc C parsing - searching for delimiters with strchr() or the like
and breaking down on that basis.

As well as being a slightly awkward mix, the current approach will not work
for adding target addresses to the rules: we can't easily split the
listening from target parts first, because the ':' delimiter could appear
multiple times for multiple port ranges, or in IPv6 addresses.  However,
without splitting the target part first, we can't first split off the
listening address and interface because the '/' delimiter could appear in
the target portion, but not the listening portion, e.g.:
    -t 12345:192.0.1.1/12345

To address this, rewrite the entirety of the parsing so we consume the
input left to right in a more-or-less recursive descent manner.  This means
we no longer rely on certain delimiters having a single meaning over the
whole input, just the next part of it.

Because of the semantics of port specs, we need to make several passes
over the list of comma separated chunks.  Previously, some of the logic was
duplicated between the two passes, making it fragile.  Now, we introduce
a parse_port_chunk() helper which we re-use in each pass to make it clearer
we parse exactly the same way on each pass.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Forwarding rules for the -[tTuU] options are parsed in fwd_rule_parse()
and fwd_rule_parse_ports().  Currently those use a mix of loosely
recursive descent parsing helpers, consuming input from left to right,
and ad-hoc C parsing - searching for delimiters with strchr() or the like
and breaking down on that basis.

As well as being a slightly awkward mix, the current approach will not work
for adding target addresses to the rules: we can't easily split the
listening from target parts first, because the ':' delimiter could appear
multiple times for multiple port ranges, or in IPv6 addresses.  However,
without splitting the target part first, we can't first split off the
listening address and interface because the '/' delimiter could appear in
the target portion, but not the listening portion, e.g.:
    -t 12345:192.0.1.1/12345

To address this, rewrite the entirety of the parsing so we consume the
input left to right in a more-or-less recursive descent manner.  This means
we no longer rely on certain delimiters having a single meaning over the
whole input, just the next part of it.

Because of the semantics of port specs, we need to make several passes
over the list of comma separated chunks.  Previously, some of the logic was
duplicated between the two passes, making it fragile.  Now, we introduce
a parse_port_chunk() helper which we re-use in each pass to make it clearer
we parse exactly the same way on each pass.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fwd_rule: Allow "all" port specs to be combined with other options</title>
<updated>2026-07-04T11:14:30+00:00</updated>
<author>
<name>David Gibson</name>
<email>david@gibson.dropbear.id.au</email>
</author>
<published>2026-07-03T03:54:44+00:00</published>
<link rel='alternate' type='text/html' href='https://passt.top/passt/commit/?id=0581b0ab0f58d5c2fa4cb06ab614055749c4404b'/>
<id>0581b0ab0f58d5c2fa4cb06ab614055749c4404b</id>
<content type='text'>
Currently we handle -t all and the like as a special case, it can't be
combined with other port specifier options.  Remove that restriction,
allowing combined options like:
     -t all,~9999          # Forward everything non-ephemeral except 9999
     -t all,auto           # Equivalent to -t auto
     -t all,33000          # Forward non-ephemeral plus port 33,000

This isn't particularly useful immediately, but will become important for
destination address specification - it provides a place to attach the
target address for "all" or exclude only mappings.  It will also work
better with some parsing reworks we want to make.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Currently we handle -t all and the like as a special case, it can't be
combined with other port specifier options.  Remove that restriction,
allowing combined options like:
     -t all,~9999          # Forward everything non-ephemeral except 9999
     -t all,auto           # Equivalent to -t auto
     -t all,33000          # Forward non-ephemeral plus port 33,000

This isn't particularly useful immediately, but will become important for
destination address specification - it provides a place to attach the
target address for "all" or exclude only mappings.  It will also work
better with some parsing reworks we want to make.

Signed-off-by: David Gibson &lt;david@gibson.dropbear.id.au&gt;
Signed-off-by: Stefano Brivio &lt;sbrivio@redhat.com&gt;
</pre>
</div>
</content>
</entry>
</feed>
