package netns // inspired from https://github.com/vishvananda/netns/blob/master/netns_linux.go#L95 import ( "fmt" "github.com/docker/docker/pkg/namesgenerator" "golang.org/x/sys/unix" "os" "path" ) // New create and persist a new namespace with random Name func New() (handle NsHandle, error error) { origins, err := Get() if err != nil { return None(), err } defer deferClose(&origins, &error) if err := unix.Unshare(unix.CLONE_NEWNET); err != nil { return None(), err } newNs, err := Get() if err != nil { return None(), err } err = newNs.persist() if err != nil { defer deferClose(&newNs, &error) return newNs, err } err = Set(origins) if err != nil { return NsHandle{Fd: 0}, err } return newNs, nil } func deferClose(origins *NsHandle, e *error) { // return main error, or defer action error if occurred if err := origins.Close(); e == nil && err != nil { e = &err } } // Delete deletes a named network namespace func Delete(ns NsHandle) error { namedPath := path.Join(bindMountPath, ns.Name) err := unix.Unmount(namedPath, unix.MNT_DETACH) if err != nil { return err } return os.Remove(namedPath) } // Get gets a handle to the current threads network namespace. func Get() (NsHandle, error) { return GetFromPath(GetPath()) } // GetPath gets path to the current threads network namespace. func GetPath() string { tid := unix.Gettid() pid := os.Getpid() return fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid) } // GetFromPath gets a handle to a network namespace // identified by the path func GetFromPath(path string) (NsHandle, error) { fd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0) if err != nil { return None(), err } name := namesgenerator.GetRandomName(0) return NsHandle{fd, name}, nil } // Set sets the current network namespace to the namespace represented // by NsHandle. func Set(ns NsHandle) error { return unix.Setns(ns.Fd, unix.CLONE_NEWNET) }