// +build linux package sandbox import ( "crypto/rand" "fmt" "os" "path/filepath" "sync" "github.com/containernetworking/plugins/pkg/ns" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/symlink" "golang.org/x/sys/unix" ) func isNSorErr(nspath string) error { return ns.IsNSorErr(nspath) } func newNetNs() (*NetNs, error) { netNS, err := ns.NewNS() if err != nil { return nil, err } return &NetNs{nn: netNS, closed: false}, nil } func getNetNs(path string) (*NetNs, error) { return &NetNs{}, nil netNS, err := ns.GetNS(path) if err != nil { return nil, err } return &NetNs{nn: netNS, closed: false, restored: true}, nil } // NetNs handles data pertaining a network namespace type NetNs struct { sync.Mutex nn ns.NetNS symlink *os.File closed bool restored bool } func (nns *NetNs) Path() string { return nns.nn.Path() } func (nns *NetNs) Close() error { return nns.nn.Close() } func (nns *NetNs) Remove() error { nns.Lock() defer nns.Unlock() if nns.closed { // netNsRemove() can be called multiple // times without returning an error. return nil } if err := nns.symlinkRemove(); err != nil { return err } if err := nns.Close(); err != nil { return err } nns.closed = true if nns.restored { // we got namespaces in the form of // /var/run/netns/cni-0d08effa-06eb-a963-f51a-e2b0eceffc5d // but /var/run on most system is symlinked to /run so we first resolve // the symlink and then try and see if it's mounted fp, err := symlink.FollowSymlinkInScope(nns.Path(), "/") if err != nil { return err } if mounted, err := mount.Mounted(fp); err == nil && mounted { if err := unix.Unmount(fp, unix.MNT_DETACH); err != nil { return err } } if nns.Path() != "" { if err := os.RemoveAll(nns.Path()); err != nil { return err } } } return nil } func (nns *NetNs) symlinkCreate(name string) error { b := make([]byte, 4) _, randErr := rand.Reader.Read(b) if randErr != nil { return randErr } nsName := fmt.Sprintf("%s-%x", name, b) symlinkPath := filepath.Join(NsRunDir, nsName) if err := os.Symlink(nns.nn.Path(), symlinkPath); err != nil { return err } fd, err := os.Open(symlinkPath) if err != nil { if removeErr := os.RemoveAll(symlinkPath); removeErr != nil { return removeErr } return err } nns.symlink = fd return nil } func (nns *NetNs) symlinkRemove() error { if err := nns.symlink.Close(); err != nil { return fmt.Errorf("failed to close net ns symlink: %v", err) } if err := os.RemoveAll(nns.symlink.Name()); err != nil { return fmt.Errorf("failed to remove net ns symlink: %v", err) } return nil } func hostNetNsPath() (string, error) { netNS, err := ns.GetCurrentNS() if err != nil { return "", err } defer netNS.Close() return netNS.Path(), nil }