package netns // inspired from https://github.com/vishvananda/netns/blob/master/nshandle_linux.go#L11 import ( "fmt" "golang.org/x/sys/unix" "os" "path" ) const bindMountPath = "/run/netns" // NsHandle is a handle to a network namespace. It can be cast directly // to an int and used as a file descriptor. type NsHandle struct { Fd int Name string } // persist and bind mount net namespace to `/run/netns` func (ns *NsHandle) persist() error { if _, err := os.Stat(bindMountPath); os.IsNotExist(err) { err = os.MkdirAll(bindMountPath, 0o755) if err != nil { return err } } namedPath := path.Join(bindMountPath, ns.Name) f, err := os.OpenFile(namedPath, os.O_CREATE|os.O_EXCL, 0o444) if err != nil { return err } err = f.Close() if err != nil { return err } err = unix.Mount(GetPath(), namedPath, "bind", unix.MS_BIND, "") if err != nil { return err } return nil } // Equal determines if two network handles refer to the same network // namespace. This is done by comparing the device and inode that the // file descriptors point to. func (ns *NsHandle) Equal(other NsHandle) bool { if *ns == other { return true } var s1, s2 unix.Stat_t if err := unix.Fstat(ns.Fd, &s1); err != nil { return false } if err := unix.Fstat(other.Fd, &s2); err != nil { return false } return (s1.Dev == s2.Dev) && (s1.Ino == s2.Ino) } // String shows the file descriptor number and its dev and inode. func (ns *NsHandle) String() string { if ns.Fd == -1 { return "NS(none)" } var s unix.Stat_t if err := unix.Fstat(ns.Fd, &s); err != nil { return fmt.Sprintf("NS(%d: unknown)", ns.Fd) } return fmt.Sprintf("NS(%d: %d, %d)", ns.Fd, s.Dev, s.Ino) } // IsOpen returns true if Close() has not been called. func (ns *NsHandle) IsOpen() bool { return ns.Fd != -1 } // Close closes the NsHandle and resets its file descriptor to -1. // It is not safe to use an NsHandle after Close() is called. func (ns *NsHandle) Close() error { if err := unix.Close(ns.Fd); err != nil { return err } ns.Fd = -1 return nil } // None gets an empty (closed) NsHandle. func None() NsHandle { return NsHandle{ Fd: -1, } }