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 } nsPath := GetPath() err = unix.Mount(nsPath, 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) } return fmt.Sprintf("NS(%d: %d, %d)", ns, 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, } }