github.com/containers/podman/v4@v4.9.4/pkg/namespaces/namespaces.go (about)

     1  package namespaces
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/containers/storage/types"
     9  )
    10  
    11  const (
    12  	bridgeType    = "bridge"
    13  	containerType = "container"
    14  	defaultType   = "default"
    15  	hostType      = "host"
    16  	noneType      = "none"
    17  	nsType        = "ns"
    18  	podType       = "pod"
    19  	privateType   = "private"
    20  	shareableType = "shareable"
    21  	slirpType     = "slirp4netns"
    22  	pastaType     = "pasta"
    23  )
    24  
    25  // KeepIDUserNsOptions defines how to keepIDmatically create a user namespace.
    26  type KeepIDUserNsOptions struct {
    27  	// UID is the target uid in the user namespace.
    28  	UID *uint32
    29  	// GID is the target uid in the user namespace.
    30  	GID *uint32
    31  }
    32  
    33  // CgroupMode represents cgroup mode in the container.
    34  type CgroupMode string
    35  
    36  // IsHost indicates whether the container uses the host's cgroup.
    37  func (n CgroupMode) IsHost() bool {
    38  	return n == hostType
    39  }
    40  
    41  // IsDefaultValue indicates whether the cgroup namespace has the default value.
    42  func (n CgroupMode) IsDefaultValue() bool {
    43  	return n == "" || n == defaultType
    44  }
    45  
    46  // IsNS indicates a cgroup namespace passed in by path (ns:<path>)
    47  func (n CgroupMode) IsNS() bool {
    48  	return strings.HasPrefix(string(n), nsType)
    49  }
    50  
    51  // NS gets the path associated with a ns:<path> cgroup ns
    52  func (n CgroupMode) NS() string {
    53  	parts := strings.SplitN(string(n), ":", 2)
    54  	if len(parts) > 1 {
    55  		return parts[1]
    56  	}
    57  	return ""
    58  }
    59  
    60  // IsContainer indicates whether the container uses a new cgroup namespace.
    61  func (n CgroupMode) IsContainer() bool {
    62  	parts := strings.SplitN(string(n), ":", 2)
    63  	return len(parts) > 1 && parts[0] == containerType
    64  }
    65  
    66  // Container returns the name of the container whose cgroup namespace is going to be used.
    67  func (n CgroupMode) Container() string {
    68  	parts := strings.SplitN(string(n), ":", 2)
    69  	if len(parts) > 1 && parts[0] == containerType {
    70  		return parts[1]
    71  	}
    72  	return ""
    73  }
    74  
    75  // IsPrivate indicates whether the container uses the a private cgroup.
    76  func (n CgroupMode) IsPrivate() bool {
    77  	return n == privateType
    78  }
    79  
    80  // Valid indicates whether the Cgroup namespace is valid.
    81  func (n CgroupMode) Valid() bool {
    82  	parts := strings.Split(string(n), ":")
    83  	switch mode := parts[0]; mode {
    84  	case "", hostType, privateType, nsType:
    85  	case containerType:
    86  		if len(parts) != 2 || parts[1] == "" {
    87  			return false
    88  		}
    89  	default:
    90  		return false
    91  	}
    92  	return true
    93  }
    94  
    95  // UsernsMode represents userns mode in the container.
    96  type UsernsMode string
    97  
    98  // IsHost indicates whether the container uses the host's userns.
    99  func (n UsernsMode) IsHost() bool {
   100  	return n == hostType
   101  }
   102  
   103  // IsKeepID indicates whether container uses a mapping where the (uid, gid) on the host is kept inside of the namespace.
   104  func (n UsernsMode) IsKeepID() bool {
   105  	parts := strings.Split(string(n), ":")
   106  	return parts[0] == "keep-id"
   107  }
   108  
   109  // IsNoMap indicates whether container uses a mapping where the (uid, gid) on the host is not present in the namespace.
   110  func (n UsernsMode) IsNoMap() bool {
   111  	return n == "nomap"
   112  }
   113  
   114  // IsAuto indicates whether container uses the "auto" userns mode.
   115  func (n UsernsMode) IsAuto() bool {
   116  	parts := strings.Split(string(n), ":")
   117  	return parts[0] == "auto"
   118  }
   119  
   120  // IsDefaultValue indicates whether the user namespace has the default value.
   121  func (n UsernsMode) IsDefaultValue() bool {
   122  	return n == "" || n == defaultType
   123  }
   124  
   125  // GetAutoOptions returns an AutoUserNsOptions with the settings to automatically set up
   126  // a user namespace.
   127  func (n UsernsMode) GetAutoOptions() (*types.AutoUserNsOptions, error) {
   128  	parts := strings.SplitN(string(n), ":", 2)
   129  	if parts[0] != "auto" {
   130  		return nil, fmt.Errorf("wrong user namespace mode")
   131  	}
   132  	options := types.AutoUserNsOptions{}
   133  	if len(parts) == 1 {
   134  		return &options, nil
   135  	}
   136  	for _, o := range strings.Split(parts[1], ",") {
   137  		v := strings.SplitN(o, "=", 2)
   138  		if len(v) != 2 {
   139  			return nil, fmt.Errorf("invalid option specified: %q", o)
   140  		}
   141  		switch v[0] {
   142  		case "size":
   143  			s, err := strconv.ParseUint(v[1], 10, 32)
   144  			if err != nil {
   145  				return nil, err
   146  			}
   147  			options.Size = uint32(s)
   148  		case "uidmapping":
   149  			mapping, err := types.ParseIDMapping([]string{v[1]}, nil, "", "")
   150  			if err != nil {
   151  				return nil, err
   152  			}
   153  			options.AdditionalUIDMappings = append(options.AdditionalUIDMappings, mapping.UIDMap...)
   154  		case "gidmapping":
   155  			mapping, err := types.ParseIDMapping(nil, []string{v[1]}, "", "")
   156  			if err != nil {
   157  				return nil, err
   158  			}
   159  			options.AdditionalGIDMappings = append(options.AdditionalGIDMappings, mapping.GIDMap...)
   160  		default:
   161  			return nil, fmt.Errorf("unknown option specified: %q", v[0])
   162  		}
   163  	}
   164  	return &options, nil
   165  }
   166  
   167  // GetKeepIDOptions returns a KeepIDUserNsOptions with the settings to keepIDmatically set up
   168  // a user namespace.
   169  func (n UsernsMode) GetKeepIDOptions() (*KeepIDUserNsOptions, error) {
   170  	parts := strings.SplitN(string(n), ":", 2)
   171  	if parts[0] != "keep-id" {
   172  		return nil, fmt.Errorf("wrong user namespace mode")
   173  	}
   174  	options := KeepIDUserNsOptions{}
   175  	if len(parts) == 1 {
   176  		return &options, nil
   177  	}
   178  	for _, o := range strings.Split(parts[1], ",") {
   179  		v := strings.SplitN(o, "=", 2)
   180  		if len(v) != 2 {
   181  			return nil, fmt.Errorf("invalid option specified: %q", o)
   182  		}
   183  		switch v[0] {
   184  		case "uid":
   185  			s, err := strconv.ParseUint(v[1], 10, 32)
   186  			if err != nil {
   187  				return nil, err
   188  			}
   189  			v := uint32(s)
   190  			options.UID = &v
   191  		case "gid":
   192  			s, err := strconv.ParseUint(v[1], 10, 32)
   193  			if err != nil {
   194  				return nil, err
   195  			}
   196  			v := uint32(s)
   197  			options.GID = &v
   198  		default:
   199  			return nil, fmt.Errorf("unknown option specified: %q", v[0])
   200  		}
   201  	}
   202  	return &options, nil
   203  }
   204  
   205  // IsPrivate indicates whether the container uses the a private userns.
   206  func (n UsernsMode) IsPrivate() bool {
   207  	return !(n.IsHost() || n.IsContainer())
   208  }
   209  
   210  // Valid indicates whether the userns is valid.
   211  func (n UsernsMode) Valid() bool {
   212  	parts := strings.Split(string(n), ":")
   213  	switch mode := parts[0]; mode {
   214  	case "", privateType, hostType, "keep-id", nsType, "auto", "nomap":
   215  	case containerType:
   216  		if len(parts) != 2 || parts[1] == "" {
   217  			return false
   218  		}
   219  	default:
   220  		return false
   221  	}
   222  	return true
   223  }
   224  
   225  // IsNS indicates a userns namespace passed in by path (ns:<path>)
   226  func (n UsernsMode) IsNS() bool {
   227  	return strings.HasPrefix(string(n), "ns:")
   228  }
   229  
   230  // NS gets the path associated with a ns:<path> userns ns
   231  func (n UsernsMode) NS() string {
   232  	parts := strings.SplitN(string(n), ":", 2)
   233  	if len(parts) > 1 {
   234  		return parts[1]
   235  	}
   236  	return ""
   237  }
   238  
   239  // IsContainer indicates whether container uses a container userns.
   240  func (n UsernsMode) IsContainer() bool {
   241  	parts := strings.SplitN(string(n), ":", 2)
   242  	return len(parts) > 1 && parts[0] == containerType
   243  }
   244  
   245  // Container is the id of the container which network this container is connected to.
   246  func (n UsernsMode) Container() string {
   247  	parts := strings.SplitN(string(n), ":", 2)
   248  	if len(parts) > 1 && parts[0] == containerType {
   249  		return parts[1]
   250  	}
   251  	return ""
   252  }
   253  
   254  // UTSMode represents the UTS namespace of the container.
   255  type UTSMode string
   256  
   257  // IsPrivate indicates whether the container uses its private UTS namespace.
   258  func (n UTSMode) IsPrivate() bool {
   259  	return !(n.IsHost())
   260  }
   261  
   262  // IsHost indicates whether the container uses the host's UTS namespace.
   263  func (n UTSMode) IsHost() bool {
   264  	return n == hostType
   265  }
   266  
   267  // IsContainer indicates whether the container uses a container's UTS namespace.
   268  func (n UTSMode) IsContainer() bool {
   269  	parts := strings.SplitN(string(n), ":", 2)
   270  	return len(parts) > 1 && parts[0] == containerType
   271  }
   272  
   273  // Container returns the name of the container whose uts namespace is going to be used.
   274  func (n UTSMode) Container() string {
   275  	parts := strings.SplitN(string(n), ":", 2)
   276  	if len(parts) > 1 && parts[0] == containerType {
   277  		return parts[1]
   278  	}
   279  	return ""
   280  }
   281  
   282  // Valid indicates whether the UTS namespace is valid.
   283  func (n UTSMode) Valid() bool {
   284  	parts := strings.Split(string(n), ":")
   285  	switch mode := parts[0]; mode {
   286  	case "", privateType, hostType:
   287  	case containerType:
   288  		if len(parts) != 2 || parts[1] == "" {
   289  			return false
   290  		}
   291  	default:
   292  		return false
   293  	}
   294  	return true
   295  }
   296  
   297  // IpcMode represents the container ipc stack.
   298  type IpcMode string
   299  
   300  // IsPrivate indicates whether the container uses its own private ipc namespace which cannot be shared.
   301  func (n IpcMode) IsPrivate() bool {
   302  	return n == privateType
   303  }
   304  
   305  // IsHost indicates whether the container shares the host's ipc namespace.
   306  func (n IpcMode) IsHost() bool {
   307  	return n == hostType
   308  }
   309  
   310  // IsShareable indicates whether the container uses its own shareable ipc namespace which can be shared.
   311  func (n IpcMode) IsShareable() bool {
   312  	return n == shareableType
   313  }
   314  
   315  // IsContainer indicates whether the container uses another container's ipc namespace.
   316  func (n IpcMode) IsContainer() bool {
   317  	parts := strings.SplitN(string(n), ":", 2)
   318  	return len(parts) > 1 && parts[0] == containerType
   319  }
   320  
   321  // IsNone indicates whether container IpcMode is set to "none".
   322  func (n IpcMode) IsNone() bool {
   323  	return n == noneType
   324  }
   325  
   326  // IsEmpty indicates whether container IpcMode is empty
   327  func (n IpcMode) IsEmpty() bool {
   328  	return n == ""
   329  }
   330  
   331  // Valid indicates whether the ipc mode is valid.
   332  func (n IpcMode) Valid() bool {
   333  	return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
   334  }
   335  
   336  // Container returns the name of the container ipc stack is going to be used.
   337  func (n IpcMode) Container() string {
   338  	parts := strings.SplitN(string(n), ":", 2)
   339  	if len(parts) > 1 && parts[0] == containerType {
   340  		return parts[1]
   341  	}
   342  	return ""
   343  }
   344  
   345  // PidMode represents the pid namespace of the container.
   346  type PidMode string
   347  
   348  // IsPrivate indicates whether the container uses its own new pid namespace.
   349  func (n PidMode) IsPrivate() bool {
   350  	return !(n.IsHost() || n.IsContainer())
   351  }
   352  
   353  // IsHost indicates whether the container uses the host's pid namespace.
   354  func (n PidMode) IsHost() bool {
   355  	return n == hostType
   356  }
   357  
   358  // IsContainer indicates whether the container uses a container's pid namespace.
   359  func (n PidMode) IsContainer() bool {
   360  	parts := strings.SplitN(string(n), ":", 2)
   361  	return len(parts) > 1 && parts[0] == containerType
   362  }
   363  
   364  // Valid indicates whether the pid namespace is valid.
   365  func (n PidMode) Valid() bool {
   366  	parts := strings.Split(string(n), ":")
   367  	switch mode := parts[0]; mode {
   368  	case "", privateType, hostType:
   369  	case containerType:
   370  		if len(parts) != 2 || parts[1] == "" {
   371  			return false
   372  		}
   373  	default:
   374  		return false
   375  	}
   376  	return true
   377  }
   378  
   379  // Container returns the name of the container whose pid namespace is going to be used.
   380  func (n PidMode) Container() string {
   381  	parts := strings.SplitN(string(n), ":", 2)
   382  	if len(parts) > 1 && parts[0] == containerType {
   383  		return parts[1]
   384  	}
   385  	return ""
   386  }
   387  
   388  // NetworkMode represents the container network stack.
   389  type NetworkMode string
   390  
   391  // IsNone indicates whether container isn't using a network stack.
   392  func (n NetworkMode) IsNone() bool {
   393  	return n == noneType
   394  }
   395  
   396  // IsHost indicates whether the container uses the host's network stack.
   397  func (n NetworkMode) IsHost() bool {
   398  	return n == hostType
   399  }
   400  
   401  // IsDefault indicates whether container uses the default network stack.
   402  func (n NetworkMode) IsDefault() bool {
   403  	return n == defaultType
   404  }
   405  
   406  // IsPrivate indicates whether container uses its private network stack.
   407  func (n NetworkMode) IsPrivate() bool {
   408  	return !(n.IsHost() || n.IsContainer())
   409  }
   410  
   411  // IsContainer indicates whether container uses a container network stack.
   412  func (n NetworkMode) IsContainer() bool {
   413  	parts := strings.SplitN(string(n), ":", 2)
   414  	return len(parts) > 1 && parts[0] == containerType
   415  }
   416  
   417  // Container is the id of the container which network this container is connected to.
   418  func (n NetworkMode) Container() string {
   419  	parts := strings.SplitN(string(n), ":", 2)
   420  	if len(parts) > 1 && parts[0] == containerType {
   421  		return parts[1]
   422  	}
   423  	return ""
   424  }
   425  
   426  // UserDefined indicates user-created network
   427  func (n NetworkMode) UserDefined() string {
   428  	if n.IsUserDefined() {
   429  		return string(n)
   430  	}
   431  	return ""
   432  }
   433  
   434  // IsBridge indicates whether container uses the bridge network stack
   435  func (n NetworkMode) IsBridge() bool {
   436  	return n == bridgeType
   437  }
   438  
   439  // IsSlirp4netns indicates if we are running a rootless network stack
   440  func (n NetworkMode) IsSlirp4netns() bool {
   441  	return n == slirpType || strings.HasPrefix(string(n), slirpType+":")
   442  }
   443  
   444  // IsPasta indicates if we are running a rootless network stack using pasta
   445  func (n NetworkMode) IsPasta() bool {
   446  	return n == pastaType || strings.HasPrefix(string(n), pastaType+":")
   447  }
   448  
   449  // IsNS indicates a network namespace passed in by path (ns:<path>)
   450  func (n NetworkMode) IsNS() bool {
   451  	return strings.HasPrefix(string(n), nsType)
   452  }
   453  
   454  // NS gets the path associated with a ns:<path> network ns
   455  func (n NetworkMode) NS() string {
   456  	parts := strings.SplitN(string(n), ":", 2)
   457  	if len(parts) > 1 {
   458  		return parts[1]
   459  	}
   460  	return ""
   461  }
   462  
   463  // IsPod returns whether the network refers to pod networking
   464  func (n NetworkMode) IsPod() bool {
   465  	return n == podType
   466  }
   467  
   468  // IsUserDefined indicates user-created network
   469  func (n NetworkMode) IsUserDefined() bool {
   470  	return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer() && !n.IsSlirp4netns() && !n.IsPasta() && !n.IsNS()
   471  }