diff options
Diffstat (limited to 'internal/namespace/namespace.go')
| -rw-r--r-- | internal/namespace/namespace.go | 32 |
1 files changed, 31 insertions, 1 deletions
diff --git a/internal/namespace/namespace.go b/internal/namespace/namespace.go index b0794a4..a1e7ad9 100644 --- a/internal/namespace/namespace.go +++ b/internal/namespace/namespace.go @@ -3,9 +3,12 @@ package namespace import ( _ "embed" "fmt" + "net" "os" "os/exec" "syscall" + + "golang.org/x/sys/unix" ) //go:embed launcher.bin @@ -123,7 +126,34 @@ func Bootstrap() error { } } } - err = syscall.Exec(launcherPath, args, os.Environ()) + + // Open the host network namespace file descriptor before unsharing. + hostNetFd, err := syscall.Open("/proc/self/ns/net", syscall.O_RDONLY, 0) + if err != nil { + return fmt.Errorf("failed to open host netns: %w", err) + } + // Clear close-on-exec so it remains open across syscall.Exec + if flags, err := unix.FcntlInt(uintptr(hostNetFd), unix.F_GETFD, 0); err == nil { + _, _ = unix.FcntlInt(uintptr(hostNetFd), unix.F_SETFD, flags&^unix.FD_CLOEXEC) + } + + env := append(os.Environ(), fmt.Sprintf("WG_WRAP_HOST_NETNS_FD=%d", hostNetFd)) + + // Open a host UDP socket on 0.0.0.0:0 before unsharing network namespace. + laddr, err := net.ResolveUDPAddr("udp", "0.0.0.0:0") + if err == nil { + if conn, err := net.ListenUDP("udp", laddr); err == nil { + if file, err := conn.File(); err == nil { + hostSocketFd := file.Fd() + if flags, err := unix.FcntlInt(hostSocketFd, unix.F_GETFD, 0); err == nil { + _, _ = unix.FcntlInt(hostSocketFd, unix.F_SETFD, flags&^unix.FD_CLOEXEC) + } + env = append(env, fmt.Sprintf("WG_WRAP_HOST_SOCKET_FD=%d", hostSocketFd)) + } + } + } + + err = syscall.Exec(launcherPath, args, env) if err != nil { return fmt.Errorf("launcher exec failed: %w", err) } |
