On Sat, May 02, 2026 at 03:25:17PM +0100, baleti wrote: > Hi, > > I'd like to propose a new option for passt, working title --no-map-host, as > a complement to the existing --no-map-gw. So, I can see that might be useful, and I'm not necessarily against it, but there are some important differences between the proposed option and --no-map-gw, that make it trickier to work out exactly what it should do and how. Further details noted below, but the key difference is that --no-map-gw behaviour arises naturally: the guest cannot reach the host's loopback unless we specifically implement translation. We do that translation by default, but --no-map-gw turns it off. That's not true for the host's external address(es) - from the guest's point of view (and even passt's, to an extent) there's no inherent difference between a host external address and the address of any random machine on the internet. To block this case we'd instead need to explicitly filter out such connection attempts. > The gap > > --no-map-gw prevents the guest from reaching host loopback services via the > gateway address mapping, which is useful. However, there is currently no > mechanism to prevent the guest from reaching services bound to the host's > real external address (e.g. 0.0.0.0:22). > > Because passt proxies outbound guest connections as the host user, a > connection from the guest to the host's own external IP is transparently > forwarded — passt opens the socket on the host side and the connection > succeeds. From the perspective of the service being connected to (e.g. > sshd), it appears as a local connection. That depends on what you mean by "local" here (unfortunately there are several possible meanings, even within kernel networking interfaces). The connection will *not* appear to come from a local scope address (127.0.0.0/8 or ::1) - it will come from one of the host's external IP addresses - typically the same one that you're connecting to. It will, obviously, come from an IP that the host owns, and will usually be routed over the host's 'lo' interface. > A concrete example with a typical setup: > >   passt -t 2222 --no-map-gw --vhost-user --socket /tmp/passt-vm > >   ss -tulpn shows: >     tcp LISTEN 0.0.0.0:22   sshd > > From inside the guest, a compromised or untrusted workload can reach sshd > directly: > >   ssh user@192.168.1.x   # host's external IP, connection succeeds Yes, although this is also true for an untrusted external machine on the host's LAN. > This also enables VM-to-VM lateral movement when multiple guests share the > same host: each guest can reach the others' forwarded ports via the host's > external IP. Right, the usual assumption here is that guest's forwarded ports are intended to be exposed to the surrounding network - that does include other VMs or containers, as well as the host and whatever's on the host's LAN. > The operator has no indication this is happening. Services bound to 0.0.0.0 > are generally considered "LAN-exposed" rather than "VM-guest-exposed", and > this assumption is silently violated. As far as I can tell something bound to 0.0.0.0 would be VM-guest-exposed with most VM network setups, not just passt, unless you explicitly introduce a firewall to catch it. > Proposed option > > --no-map-host, which would cause passt to drop or reject TCP/UDP connections > from the guest whose destination matches any of the host's own configured > addresses (the same addresses passt already knows about for DHCP/NDP > assignment purposes). So, when the guest is sharing the host's IP (default behaviour) the host's address is already implicitly blocked unless -map-guest-addr is also specified, simply because if the guest tries to send to the host's external address it will instead address itself. However, the guest does have the ability to ignore the suggested IP, so that's not really enforced. Enforcing it raises several edge cases that need consideration though: * If the host has several external addresses, do we want to block all of them? One of them? Some of them? * If the host changes external address, how do we update the filtering to cover the new address? We're looking (for other reasons) to introduce a netlink monitor to track host address changes, which could be used for this. However the update would not be instant. Is a short window where the old/new address could be accessed acceptable? These semantics would need to be pinned down in order to implement this. > An alternative spelling --map-host-addr none modelled on --map-host-loopback > none would also be consistent with the existing option naming. Right, I don't like that naming because although the effects are analagous from the point of view of your usecase, they're very different in terms of what they mean internally (an explicit filter versus disabling a translation). > This would stay entirely within passt's existing socket-layer design and > require no new privileges. No, but it does need new filtering logic to be implemented (but we're kind of working on that already, see below). > Why this matters for rootless setups > > The primary audience for passt is rootless VM deployments where TAP+bridge > (the traditional isolation mechanism) is not available without privilege. In > these setups, passt is the only network layer, so operators rely on it to > provide whatever isolation is possible. --no-map-gw is a good step in that > direction; --no-map-host would close the remaining obvious gap. This doesn't fully make sense to me - AFAICT, TAP-bridges would also leave the host's external address exposed to the VMs, unless filtered by an additional mechanism (e.g. iptables / nftables). > Happy to discuss or test patches. Thanks for the project — it's been very > useful. Thoughts on possible ways to achieve what you're looking for. # Existing approaches ## --outbound-if4 and --outbound-if6 These options let you route VM traffic explicitly to specific host interface. That won't directly make host addresses inaccessible, but might be enough to stop it appearing as "local". You'd have to check for the details of your use case. ## Isolate VMs within a netns You can create a network namespace using unshare -Un, and run your VM along with the associated passt within it. That lets the namespace owner configure routing between it and the host as you like, including explicit filters, if you want. # Upcoming approaches ## Forwarding tables We're in the process of implementing much more flexible forwarding / filtering rules, which should make this a lot more feasible. We hope to merge the first draft pretty soon, but that will only over incoming and "spliced" (for containers) connections. We do plan to extend that to filtering outbound connections as well though. That would certainly allow you to block specific addresses from the VMs. This is just waiting on the time to implement it. ## Multiple guest address handling Only indirectly related, but we're also working on better handling of multiple guest addresses, allowing (amongst other things) all the host's addresses to be reflected in the guest, not just one. We hadn't discussed it but we could potentially add to that enforcement that the guest only use the addresses it's told do, which would also effectively block host addresses from the guest (without --map-guest-addr). There would likely be unavoidable races in updating that for host address changes, however. -- 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