On Mon, 5 Jan 2026 19:28:48 +1100
David Gibson
We need to support (as best we can) older kernels which don't allow unprivilieged processes to use the SO_BINDTODEVICE socket option.
Nit: unprivileged
Fallcaks for that case are controlled by the c->no_bindtodevice variable.
Fallbacks
Currently testing behaviour of those fallbacks requires setting up a test system with a kernel that doesn't support the option, which is pretty awkward. We can test it almost as well and much more easily by adding a command line option to explicitly disable use of SO_BINDTODEVICE.
It's kind of hard to understand if this patch entirely does that, I think. We still have a separate, implicit probing of SO_BINDTODEVICE in sock_l4_(), which is perhaps excluded by c->no_bindtodevice (but then the comment is misleading?).
Like --no-splice this is envisaged as something for developers' and testers' convenience, not a supported option for end users. The man page text reflects that.
I never really understood the point of --no-splice, as there was no user request whatsoever behind it, but fine, the argument was that it added some needed functionality, even though I couldn't quite grasp which one it was. However, with this, the question is where we draw the line. There are probably other options we could use to make debugging or testing slightly simpler, but if they don't offer actual functionality, we always kept them out so far. That's because we already have a long list of options and making it unnecessarily longer is a disservice to users, I think. Would using something like this: sed -i 's/(\(setsockopt([a-z]*, SOL_SOCKET, SO_BINDTODEVICE\)/((errno = EPERM) || \1/g' *.c be totally outrageous, for testing purposes? It has the advantage of making it easier to verify if we're really disabling the usage of SO_BINDTODEVICE on all the paths (together with grep / git / editors), and not introducing additional command line options. Another trick I use sometimes to selectively disable or enable kernel features is to handle system calls via seitan, in this case the (simple) recipe would something like: [ { "match": [ { "setsockopt": { "level": socket", "name": "bindtodevice" } } ], "return": { "value": "EPERM", "error": -1 } } ] but I haven't implemented setsockopt() yet. :(
Signed-off-by: David Gibson
--- conf.c | 2 ++ passt.1 | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/conf.c b/conf.c index ceb9aa55..70ea168c 100644 --- a/conf.c +++ b/conf.c @@ -962,6 +962,7 @@ static void usage(const char *name, FILE *f, int status) " --no-ndp Disable NDP responses\n" " --no-dhcpv6 Disable DHCPv6 server\n" " --no-ra Disable router advertisements\n" + " --no-bindtodevice Disable SO_BINDTODEVICE\n" " --freebind Bind to any address for forwarding\n" " --no-map-gw Don't map gateway address to host\n" " -4, --ipv4-only Enable IPv4 operation only\n" @@ -1454,6 +1455,7 @@ void conf(struct ctx *c, int argc, char **argv) {"no-dhcpv6", no_argument, &c->no_dhcpv6, 1 }, {"no-ndp", no_argument, &c->no_ndp, 1 }, {"no-ra", no_argument, &c->no_ra, 1 }, + {"no-bindtodevice", no_argument, &c->no_bindtodevice, 1}, {"no-splice", no_argument, &c->no_splice, 1 }, {"freebind", no_argument, &c->freebind, 1 }, {"no-map-gw", no_argument, &no_map_gw, 1 }, diff --git a/passt.1 b/passt.1 index db0d6620..4859d9e5 100644 --- a/passt.1 +++ b/passt.1 @@ -348,6 +348,12 @@ namespace will be silently dropped. Disable Router Advertisements. Router Solicitations coming from guest or target namespace will be ignored.
+.TP +.BR \-\-no-bindtodevice +Development/testing option, do not use. Disables use of +SO_BINDTODEVICE socket option. Implicitly enabled on older kernels +which don't permit unprivileged use of SO_BINDTODEVICE. + .TP .BR \-\-freebind Allow any binding address to be specified for \fB-t\fR and \fB-u\fR
The change looks otherwise good to me... I just hope we can avoid it somehow, but if not, so be it. -- Stefano