WireGuard / wgctrl-go

Package wgctrl enables control of WireGuard interfaces on multiple platforms.
https://godoc.org/golang.zx2c4.com/wireguard/wgctrl
MIT License
727 stars 85 forks source link

wgctrl: specify network namespace #61

Closed g00nix closed 3 years ago

g00nix commented 5 years ago

There already is support within netlink for creating getting a socket to a specific netns, however when dialing, the client passes nil instead of a new netlink.Config. This would still lead to unix.Setns in the end, and you still need to find the fd first, but it provides better leverage over network namespaces. I think this could be used to allow a new wgctrl.NewClientWithNSfunction (with a better name than I just thought of).

I think there would also be an even better approach. Instead of using unix.Setns, there are already examples from other projects where unix.Bind got used. From what I see, unix.Bind is already used but only after the new thread gets created with newLockedNetNSGoroutine. I think it is possible to go straight away for a socket to another network namespace, without forcing an OS thread with runtime.LockOSThread().

If you think I am on a good path here, please let me know and I will try to dig deeper, fork the projects and try this out.

mdlayher commented 5 years ago

think this could be used to allow a new wgctrl.NewClientWithNS function (with a better name than I just thought of).

I'm still considering adding a Config structure, but haven't made a firm decision either way yet.

I think it is possible to go straight away for a socket to another network namespace, without forcing an OS thread with runtime.LockOSThread().

Unfortunately this is not the case. None of the fields specified in the sockaddr structure can be used to set a network namespace.

   Address formats
       The sockaddr_nl structure describes a netlink client in user space or in the kernel.  A sockaddr_nl can be either unicast (only  sent  to
       one peer) or sent to netlink multicast groups (nl_groups not equal 0).

           struct sockaddr_nl {
               sa_family_t     nl_family;  /* AF_NETLINK */
               unsigned short  nl_pad;     /* Zero */
               pid_t           nl_pid;     /* Port ID */
               __u32           nl_groups;  /* Multicast groups mask */
           };
g00nix commented 5 years ago

Unfortunately this is not the case. None of the fields specified in the sockaddr structure can be used to set a network namespace.

You are right. I just had to read the next 70 lines from the example I linked yesterday. That project does the same thing (uses LockOSThread to switch netns and binds after that).

Thank you for the answer and for considering the new config structure. Have a nice weekend!

mdlayher commented 3 years ago

I know it's been quite a while but I don't think it makes sense to expose something like this in the high level, cross-platform interface. A knowledgeable caller can run their application or goroutine (OS thread) in a different network namespace and things should just work, but I'd rather not encourage it at an API layer level.

g00nix commented 3 years ago

Yes, it's been almost 2 years. In the meantime decided to run one separate process in each network namespace, avoiding the problem completely.