github.com/moby/docker@v26.1.3+incompatible/daemon/container_operations.go (about)

     1  // FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
     2  //go:build go1.19
     3  
     4  package daemon // import "github.com/docker/docker/daemon"
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"os"
    12  	"path"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/containerd/log"
    17  	containertypes "github.com/docker/docker/api/types/container"
    18  	"github.com/docker/docker/api/types/events"
    19  	networktypes "github.com/docker/docker/api/types/network"
    20  	"github.com/docker/docker/container"
    21  	"github.com/docker/docker/daemon/config"
    22  	"github.com/docker/docker/daemon/network"
    23  	"github.com/docker/docker/errdefs"
    24  	"github.com/docker/docker/internal/multierror"
    25  	"github.com/docker/docker/internal/sliceutil"
    26  	"github.com/docker/docker/libnetwork"
    27  	"github.com/docker/docker/libnetwork/netlabel"
    28  	"github.com/docker/docker/libnetwork/options"
    29  	"github.com/docker/docker/libnetwork/scope"
    30  	"github.com/docker/docker/libnetwork/types"
    31  	"github.com/docker/docker/opts"
    32  	"github.com/docker/docker/pkg/stringid"
    33  	"github.com/docker/docker/runconfig"
    34  	"github.com/docker/go-connections/nat"
    35  )
    36  
    37  func ipAddresses(ips []net.IP) []string {
    38  	var addrs []string
    39  	for _, ip := range ips {
    40  		addrs = append(addrs, ip.String())
    41  	}
    42  	return addrs
    43  }
    44  
    45  func (daemon *Daemon) buildSandboxOptions(cfg *config.Config, container *container.Container) ([]libnetwork.SandboxOption, error) {
    46  	var sboxOptions []libnetwork.SandboxOption
    47  	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname), libnetwork.OptionDomainname(container.Config.Domainname))
    48  
    49  	if container.HostConfig.NetworkMode.IsHost() {
    50  		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
    51  	} else {
    52  		// OptionUseExternalKey is mandatory for userns support.
    53  		// But optional for non-userns support
    54  		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
    55  	}
    56  
    57  	// Add platform-specific Sandbox options.
    58  	if err := buildSandboxPlatformOptions(container, cfg, &sboxOptions); err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	if len(container.HostConfig.DNS) > 0 {
    63  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(container.HostConfig.DNS))
    64  	} else if len(cfg.DNS) > 0 {
    65  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(ipAddresses(cfg.DNS)))
    66  	}
    67  	if len(container.HostConfig.DNSSearch) > 0 {
    68  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(container.HostConfig.DNSSearch))
    69  	} else if len(cfg.DNSSearch) > 0 {
    70  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(cfg.DNSSearch))
    71  	}
    72  	if len(container.HostConfig.DNSOptions) > 0 {
    73  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(container.HostConfig.DNSOptions))
    74  	} else if len(cfg.DNSOptions) > 0 {
    75  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(cfg.DNSOptions))
    76  	}
    77  
    78  	for _, extraHost := range container.HostConfig.ExtraHosts {
    79  		// allow IPv6 addresses in extra hosts; only split on first ":"
    80  		if _, err := opts.ValidateExtraHost(extraHost); err != nil {
    81  			return nil, err
    82  		}
    83  		host, ip, _ := strings.Cut(extraHost, ":")
    84  		// If the IP Address is a string called "host-gateway", replace this
    85  		// value with the IP address stored in the daemon level HostGatewayIP
    86  		// config variable
    87  		if ip == opts.HostGatewayName {
    88  			gateway := cfg.HostGatewayIP.String()
    89  			if gateway == "" {
    90  				return nil, fmt.Errorf("unable to derive the IP value for host-gateway")
    91  			}
    92  			ip = gateway
    93  		}
    94  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(host, ip))
    95  	}
    96  
    97  	bindings := make(nat.PortMap)
    98  	if container.HostConfig.PortBindings != nil {
    99  		for p, b := range container.HostConfig.PortBindings {
   100  			bindings[p] = []nat.PortBinding{}
   101  			for _, bb := range b {
   102  				bindings[p] = append(bindings[p], nat.PortBinding{
   103  					HostIP:   bb.HostIP,
   104  					HostPort: bb.HostPort,
   105  				})
   106  			}
   107  		}
   108  	}
   109  
   110  	// TODO(thaJeztah): Move this code to a method on nat.PortSet.
   111  	ports := make([]nat.Port, 0, len(container.Config.ExposedPorts))
   112  	for p := range container.Config.ExposedPorts {
   113  		ports = append(ports, p)
   114  	}
   115  	nat.SortPortMap(ports, bindings)
   116  
   117  	var (
   118  		publishedPorts []types.PortBinding
   119  		exposedPorts   []types.TransportPort
   120  	)
   121  	for _, port := range ports {
   122  		portProto := types.ParseProtocol(port.Proto())
   123  		portNum := uint16(port.Int())
   124  		exposedPorts = append(exposedPorts, types.TransportPort{
   125  			Proto: portProto,
   126  			Port:  portNum,
   127  		})
   128  
   129  		for _, binding := range bindings[port] {
   130  			newP, err := nat.NewPort(nat.SplitProtoPort(binding.HostPort))
   131  			var portStart, portEnd int
   132  			if err == nil {
   133  				portStart, portEnd, err = newP.Range()
   134  			}
   135  			if err != nil {
   136  				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding.HostPort, err)
   137  			}
   138  			publishedPorts = append(publishedPorts, types.PortBinding{
   139  				Proto:       portProto,
   140  				Port:        portNum,
   141  				HostIP:      net.ParseIP(binding.HostIP),
   142  				HostPort:    uint16(portStart),
   143  				HostPortEnd: uint16(portEnd),
   144  			})
   145  		}
   146  
   147  		if container.HostConfig.PublishAllPorts && len(bindings[port]) == 0 {
   148  			publishedPorts = append(publishedPorts, types.PortBinding{
   149  				Proto: portProto,
   150  				Port:  portNum,
   151  			})
   152  		}
   153  	}
   154  
   155  	sboxOptions = append(sboxOptions, libnetwork.OptionPortMapping(publishedPorts), libnetwork.OptionExposedPorts(exposedPorts))
   156  
   157  	// Legacy Link feature is supported only for the default bridge network.
   158  	// return if this call to build join options is not for default bridge network
   159  	// Legacy Link is only supported by docker run --link
   160  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   161  	bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
   162  	if !ok || bridgeSettings.EndpointSettings == nil || bridgeSettings.EndpointID == "" {
   163  		return sboxOptions, nil
   164  	}
   165  
   166  	var (
   167  		childEndpoints []string
   168  		cEndpointID    string
   169  	)
   170  	for linkAlias, child := range daemon.children(container) {
   171  		if !isLinkable(child) {
   172  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   173  		}
   174  		_, alias := path.Split(linkAlias)
   175  		// allow access to the linked container via the alias, real name, and container hostname
   176  		aliasList := alias + " " + child.Config.Hostname
   177  		// only add the name if alias isn't equal to the name
   178  		if alias != child.Name[1:] {
   179  			aliasList = aliasList + " " + child.Name[1:]
   180  		}
   181  		defaultNW := child.NetworkSettings.Networks[defaultNetName]
   182  		if defaultNW.IPAddress != "" {
   183  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, defaultNW.IPAddress))
   184  		}
   185  		if defaultNW.GlobalIPv6Address != "" {
   186  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, defaultNW.GlobalIPv6Address))
   187  		}
   188  		cEndpointID = defaultNW.EndpointID
   189  		if cEndpointID != "" {
   190  			childEndpoints = append(childEndpoints, cEndpointID)
   191  		}
   192  	}
   193  
   194  	var parentEndpoints []string
   195  	for alias, parent := range daemon.parents(container) {
   196  		if cfg.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
   197  			continue
   198  		}
   199  
   200  		_, alias = path.Split(alias)
   201  		log.G(context.TODO()).Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
   202  		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(parent.ID, alias, bridgeSettings.IPAddress))
   203  		if cEndpointID != "" {
   204  			parentEndpoints = append(parentEndpoints, cEndpointID)
   205  		}
   206  	}
   207  
   208  	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(options.Generic{
   209  		netlabel.GenericData: options.Generic{
   210  			"ParentEndpoints": parentEndpoints,
   211  			"ChildEndpoints":  childEndpoints,
   212  		},
   213  	}))
   214  	return sboxOptions, nil
   215  }
   216  
   217  func (daemon *Daemon) updateNetworkSettings(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error {
   218  	if container.NetworkSettings == nil {
   219  		container.NetworkSettings = &network.Settings{}
   220  	}
   221  	if container.NetworkSettings.Networks == nil {
   222  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   223  	}
   224  
   225  	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
   226  		return runconfig.ErrConflictHostNetwork
   227  	}
   228  
   229  	for s, v := range container.NetworkSettings.Networks {
   230  		sn, err := daemon.FindNetwork(getNetworkID(s, v.EndpointSettings))
   231  		if err != nil {
   232  			continue
   233  		}
   234  
   235  		if sn.Name() == n.Name() {
   236  			// If the network scope is swarm, then this
   237  			// is an attachable network, which may not
   238  			// be locally available previously.
   239  			// So always update.
   240  			if n.Scope() == scope.Swarm {
   241  				continue
   242  			}
   243  			// Avoid duplicate config
   244  			return nil
   245  		}
   246  		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
   247  			!containertypes.NetworkMode(n.Type()).IsPrivate() {
   248  			return runconfig.ErrConflictSharedNetwork
   249  		}
   250  		if containertypes.NetworkMode(sn.Name()).IsNone() ||
   251  			containertypes.NetworkMode(n.Name()).IsNone() {
   252  			return runconfig.ErrConflictNoNetwork
   253  		}
   254  	}
   255  
   256  	container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
   257  		EndpointSettings: endpointConfig,
   258  	}
   259  
   260  	return nil
   261  }
   262  
   263  func (daemon *Daemon) updateEndpointNetworkSettings(cfg *config.Config, container *container.Container, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
   264  	if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
   265  		return err
   266  	}
   267  
   268  	if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
   269  		container.NetworkSettings.Bridge = cfg.BridgeConfig.Iface
   270  	}
   271  
   272  	return nil
   273  }
   274  
   275  // UpdateNetwork is used to update the container's network (e.g. when linked containers
   276  // get removed/unlinked).
   277  func (daemon *Daemon) updateNetwork(cfg *config.Config, container *container.Container) error {
   278  	var (
   279  		start = time.Now()
   280  		ctrl  = daemon.netController
   281  		sid   = container.NetworkSettings.SandboxID
   282  	)
   283  
   284  	sb, err := ctrl.SandboxByID(sid)
   285  	if err != nil {
   286  		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
   287  	}
   288  
   289  	// Find if container is connected to the default bridge network
   290  	var n *libnetwork.Network
   291  	for name, v := range container.NetworkSettings.Networks {
   292  		sn, err := daemon.FindNetwork(getNetworkID(name, v.EndpointSettings))
   293  		if err != nil {
   294  			continue
   295  		}
   296  		if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
   297  			n = sn
   298  			break
   299  		}
   300  	}
   301  
   302  	if n == nil {
   303  		// Not connected to the default bridge network; Nothing to do
   304  		return nil
   305  	}
   306  
   307  	sbOptions, err := daemon.buildSandboxOptions(cfg, container)
   308  	if err != nil {
   309  		return fmt.Errorf("Update network failed: %v", err)
   310  	}
   311  
   312  	if err := sb.Refresh(sbOptions...); err != nil {
   313  		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
   314  	}
   315  
   316  	networkActions.WithValues("update").UpdateSince(start)
   317  
   318  	return nil
   319  }
   320  
   321  func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (*libnetwork.Network, *networktypes.NetworkingConfig, error) {
   322  	id := getNetworkID(idOrName, epConfig)
   323  
   324  	n, err := daemon.FindNetwork(id)
   325  	if err != nil {
   326  		// We should always be able to find the network for a managed container.
   327  		if container.Managed {
   328  			return nil, nil, err
   329  		}
   330  	}
   331  
   332  	// If we found a network and if it is not dynamically created
   333  	// we should never attempt to attach to that network here.
   334  	if n != nil {
   335  		if container.Managed || !n.Dynamic() {
   336  			return n, nil, nil
   337  		}
   338  		// Throw an error if the container is already attached to the network
   339  		if container.NetworkSettings.Networks != nil {
   340  			networkName := n.Name()
   341  			containerName := strings.TrimPrefix(container.Name, "/")
   342  			if nw, ok := container.NetworkSettings.Networks[networkName]; ok && nw.EndpointID != "" {
   343  				err := fmt.Errorf("%s is already attached to network %s", containerName, networkName)
   344  				return n, nil, errdefs.Conflict(err)
   345  			}
   346  		}
   347  	}
   348  
   349  	var addresses []string
   350  	if epConfig != nil && epConfig.IPAMConfig != nil {
   351  		if epConfig.IPAMConfig.IPv4Address != "" {
   352  			addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
   353  		}
   354  		if epConfig.IPAMConfig.IPv6Address != "" {
   355  			addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
   356  		}
   357  	}
   358  
   359  	if n == nil && daemon.attachableNetworkLock != nil {
   360  		daemon.attachableNetworkLock.Lock(id)
   361  		defer daemon.attachableNetworkLock.Unlock(id)
   362  	}
   363  
   364  	retryCount := 0
   365  	var nwCfg *networktypes.NetworkingConfig
   366  	for {
   367  		// In all other cases, attempt to attach to the network to
   368  		// trigger attachment in the swarm cluster manager.
   369  		if daemon.clusterProvider != nil {
   370  			var err error
   371  			nwCfg, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses)
   372  			if err != nil {
   373  				return nil, nil, err
   374  			}
   375  		}
   376  
   377  		n, err = daemon.FindNetwork(id)
   378  		if err != nil {
   379  			if daemon.clusterProvider != nil {
   380  				if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil {
   381  					log.G(context.TODO()).Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
   382  				}
   383  			}
   384  
   385  			// Retry network attach again if we failed to
   386  			// find the network after successful
   387  			// attachment because the only reason that
   388  			// would happen is if some other container
   389  			// attached to the swarm scope network went down
   390  			// and removed the network while we were in
   391  			// the process of attaching.
   392  			if nwCfg != nil {
   393  				if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
   394  					if retryCount >= 5 {
   395  						return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName)
   396  					}
   397  					retryCount++
   398  					continue
   399  				}
   400  			}
   401  
   402  			return nil, nil, err
   403  		}
   404  
   405  		break
   406  	}
   407  
   408  	// This container has attachment to a swarm scope
   409  	// network. Update the container network settings accordingly.
   410  	container.NetworkSettings.HasSwarmEndpoint = true
   411  	return n, nwCfg, nil
   412  }
   413  
   414  // updateContainerNetworkSettings updates the network settings
   415  func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) {
   416  	var n *libnetwork.Network
   417  
   418  	mode := container.HostConfig.NetworkMode
   419  	if container.Config.NetworkDisabled || mode.IsContainer() {
   420  		return
   421  	}
   422  
   423  	networkName := mode.NetworkName()
   424  
   425  	if mode.IsUserDefined() {
   426  		var err error
   427  
   428  		n, err = daemon.FindNetwork(networkName)
   429  		if err == nil {
   430  			networkName = n.Name()
   431  		}
   432  	}
   433  
   434  	if container.NetworkSettings == nil {
   435  		container.NetworkSettings = &network.Settings{}
   436  	}
   437  
   438  	if len(endpointsConfig) > 0 {
   439  		if container.NetworkSettings.Networks == nil {
   440  			container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   441  		}
   442  
   443  		for name, epConfig := range endpointsConfig {
   444  			container.NetworkSettings.Networks[name] = &network.EndpointSettings{
   445  				EndpointSettings: epConfig,
   446  				// At this point, during container creation, epConfig.MacAddress is the
   447  				// configured value from the API. If there is no configured value, the
   448  				// same field will later be used to store a generated MAC address. So,
   449  				// remember the requested address now.
   450  				DesiredMacAddress: epConfig.MacAddress,
   451  			}
   452  		}
   453  	}
   454  
   455  	if container.NetworkSettings.Networks == nil {
   456  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   457  		container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
   458  			EndpointSettings: &networktypes.EndpointSettings{},
   459  		}
   460  	}
   461  
   462  	if !mode.IsUserDefined() {
   463  		return
   464  	}
   465  	// Make sure to internally store the per network endpoint config by network name
   466  	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
   467  		return
   468  	}
   469  
   470  	if n != nil {
   471  		if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   472  			container.NetworkSettings.Networks[networkName] = nwConfig
   473  			delete(container.NetworkSettings.Networks, n.ID())
   474  			return
   475  		}
   476  	}
   477  }
   478  
   479  func (daemon *Daemon) allocateNetwork(cfg *config.Config, container *container.Container) (retErr error) {
   480  	if daemon.netController == nil {
   481  		return nil
   482  	}
   483  
   484  	start := time.Now()
   485  
   486  	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
   487  	if err := daemon.netController.SandboxDestroy(container.ID); err != nil {
   488  		log.G(context.TODO()).WithError(err).Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
   489  	}
   490  
   491  	if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
   492  		return nil
   493  	}
   494  
   495  	updateSettings := false
   496  	if len(container.NetworkSettings.Networks) == 0 {
   497  		daemon.updateContainerNetworkSettings(container, nil)
   498  		updateSettings = true
   499  	}
   500  
   501  	// always connect default network first since only default
   502  	// network mode support link and we need do some setting
   503  	// on sandbox initialize for link, but the sandbox only be initialized
   504  	// on first network connecting.
   505  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   506  	if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
   507  		cleanOperationalData(nConf)
   508  		if err := daemon.connectToNetwork(cfg, container, defaultNetName, nConf, updateSettings); err != nil {
   509  			return err
   510  		}
   511  	}
   512  
   513  	// the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks"
   514  	networks := make(map[string]*network.EndpointSettings)
   515  	for n, epConf := range container.NetworkSettings.Networks {
   516  		if n == defaultNetName {
   517  			continue
   518  		}
   519  
   520  		networks[n] = epConf
   521  	}
   522  
   523  	for netName, epConf := range networks {
   524  		cleanOperationalData(epConf)
   525  		if err := daemon.connectToNetwork(cfg, container, netName, epConf, updateSettings); err != nil {
   526  			return err
   527  		}
   528  	}
   529  
   530  	// If the container is not to be connected to any network,
   531  	// create its network sandbox now if not present
   532  	if len(networks) == 0 {
   533  		if _, err := daemon.netController.GetSandbox(container.ID); err != nil {
   534  			if !errdefs.IsNotFound(err) {
   535  				return err
   536  			}
   537  
   538  			sbOptions, err := daemon.buildSandboxOptions(cfg, container)
   539  			if err != nil {
   540  				return err
   541  			}
   542  			sb, err := daemon.netController.NewSandbox(container.ID, sbOptions...)
   543  			if err != nil {
   544  				return err
   545  			}
   546  			setNetworkSandbox(container, sb)
   547  			defer func() {
   548  				if retErr != nil {
   549  					sb.Delete()
   550  				}
   551  			}()
   552  		}
   553  	}
   554  
   555  	if _, err := container.WriteHostConfig(); err != nil {
   556  		return err
   557  	}
   558  	networkActions.WithValues("allocate").UpdateSince(start)
   559  	return nil
   560  }
   561  
   562  // validateEndpointSettings checks whether the given epConfig is valid. The nw parameter can be nil, in which case it
   563  // won't try to check if the endpoint IP addresses are within network's subnets.
   564  func validateEndpointSettings(nw *libnetwork.Network, nwName string, epConfig *networktypes.EndpointSettings) error {
   565  	if epConfig == nil {
   566  		return nil
   567  	}
   568  
   569  	ipamConfig := &networktypes.EndpointIPAMConfig{}
   570  	if epConfig.IPAMConfig != nil {
   571  		ipamConfig = epConfig.IPAMConfig
   572  	}
   573  
   574  	var errs []error
   575  
   576  	// TODO(aker): move this into api/types/network/endpoint.go once enableIPOnPredefinedNetwork and
   577  	//  serviceDiscoveryOnDefaultNetwork are removed.
   578  	if !containertypes.NetworkMode(nwName).IsUserDefined() {
   579  		hasStaticAddresses := ipamConfig.IPv4Address != "" || ipamConfig.IPv6Address != ""
   580  		// On Linux, user specified IP address is accepted only by networks with user specified subnets.
   581  		if hasStaticAddresses && !enableIPOnPredefinedNetwork() {
   582  			errs = append(errs, runconfig.ErrUnsupportedNetworkAndIP)
   583  		}
   584  		if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() {
   585  			errs = append(errs, runconfig.ErrUnsupportedNetworkAndAlias)
   586  		}
   587  	}
   588  
   589  	// TODO(aker): add a proper multierror.Append
   590  	if err := ipamConfig.Validate(); err != nil {
   591  		errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...)
   592  	}
   593  
   594  	if nw != nil {
   595  		_, _, v4Configs, v6Configs := nw.IpamConfig()
   596  
   597  		var nwIPv4Subnets, nwIPv6Subnets []networktypes.NetworkSubnet
   598  		for _, nwIPAMConfig := range v4Configs {
   599  			nwIPv4Subnets = append(nwIPv4Subnets, nwIPAMConfig)
   600  		}
   601  		for _, nwIPAMConfig := range v6Configs {
   602  			nwIPv6Subnets = append(nwIPv6Subnets, nwIPAMConfig)
   603  		}
   604  
   605  		// TODO(aker): add a proper multierror.Append
   606  		if err := ipamConfig.IsInRange(nwIPv4Subnets, nwIPv6Subnets); err != nil {
   607  			errs = append(errs, err.(interface{ Unwrap() []error }).Unwrap()...)
   608  		}
   609  	}
   610  
   611  	if epConfig.MacAddress != "" {
   612  		_, err := net.ParseMAC(epConfig.MacAddress)
   613  		if err != nil {
   614  			return fmt.Errorf("invalid MAC address %s", epConfig.MacAddress)
   615  		}
   616  	}
   617  
   618  	if err := multierror.Join(errs...); err != nil {
   619  		return fmt.Errorf("invalid endpoint settings:\n%w", err)
   620  	}
   621  
   622  	return nil
   623  }
   624  
   625  // cleanOperationalData resets the operational data from the passed endpoint settings
   626  func cleanOperationalData(es *network.EndpointSettings) {
   627  	es.EndpointID = ""
   628  	es.Gateway = ""
   629  	es.IPAddress = ""
   630  	es.IPPrefixLen = 0
   631  	es.IPv6Gateway = ""
   632  	es.GlobalIPv6Address = ""
   633  	es.GlobalIPv6PrefixLen = 0
   634  	es.MacAddress = ""
   635  	if es.IPAMOperational {
   636  		es.IPAMConfig = nil
   637  	}
   638  }
   639  
   640  func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
   641  	// Set up DNS names for a user defined network, and for the default 'nat'
   642  	// network on Windows (IsBridge() returns true for nat).
   643  	if containertypes.NetworkMode(n.Name()).IsUserDefined() ||
   644  		(serviceDiscoveryOnDefaultNetwork() && containertypes.NetworkMode(n.Name()).IsBridge()) {
   645  		endpointConfig.DNSNames = buildEndpointDNSNames(container, endpointConfig.Aliases)
   646  	}
   647  
   648  	if err := validateEndpointSettings(n, n.Name(), endpointConfig); err != nil {
   649  		return errdefs.InvalidParameter(err)
   650  	}
   651  
   652  	if updateSettings {
   653  		if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
   654  			return err
   655  		}
   656  	}
   657  	return nil
   658  }
   659  
   660  // buildEndpointDNSNames constructs the list of DNSNames that should be assigned to a given endpoint. The order within
   661  // the returned slice is important as the first entry will be used to generate the PTR records (for IPv4 and v6)
   662  // associated to this endpoint.
   663  func buildEndpointDNSNames(ctr *container.Container, aliases []string) []string {
   664  	var dnsNames []string
   665  
   666  	if ctr.Name != "" {
   667  		dnsNames = append(dnsNames, strings.TrimPrefix(ctr.Name, "/"))
   668  	}
   669  
   670  	dnsNames = append(dnsNames, aliases...)
   671  
   672  	if ctr.ID != "" {
   673  		dnsNames = append(dnsNames, stringid.TruncateID(ctr.ID))
   674  	}
   675  
   676  	if ctr.Config.Hostname != "" {
   677  		dnsNames = append(dnsNames, ctr.Config.Hostname)
   678  	}
   679  
   680  	return sliceutil.Dedup(dnsNames)
   681  }
   682  
   683  func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.Container, idOrName string, endpointConfig *network.EndpointSettings, updateSettings bool) (retErr error) {
   684  	start := time.Now()
   685  	if container.HostConfig.NetworkMode.IsContainer() {
   686  		return runconfig.ErrConflictSharedNetwork
   687  	}
   688  	if cfg.DisableBridge && containertypes.NetworkMode(idOrName).IsBridge() {
   689  		container.Config.NetworkDisabled = true
   690  		return nil
   691  	}
   692  	if endpointConfig == nil {
   693  		endpointConfig = &network.EndpointSettings{
   694  			EndpointSettings: &networktypes.EndpointSettings{},
   695  		}
   696  	}
   697  
   698  	n, nwCfg, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig.EndpointSettings)
   699  	if err != nil {
   700  		return err
   701  	}
   702  	if n == nil {
   703  		return nil
   704  	}
   705  	nwName := n.Name()
   706  
   707  	if idOrName != container.HostConfig.NetworkMode.NetworkName() {
   708  		if err := daemon.normalizeNetMode(container); err != nil {
   709  			return err
   710  		}
   711  	}
   712  
   713  	endpointConfig.IPAMOperational = false
   714  	if nwCfg != nil {
   715  		if epConfig, ok := nwCfg.EndpointsConfig[nwName]; ok {
   716  			if endpointConfig.IPAMConfig == nil || (endpointConfig.IPAMConfig.IPv4Address == "" && endpointConfig.IPAMConfig.IPv6Address == "" && len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
   717  				endpointConfig.IPAMOperational = true
   718  			}
   719  
   720  			// copy IPAMConfig and NetworkID from epConfig via AttachNetwork
   721  			endpointConfig.IPAMConfig = epConfig.IPAMConfig
   722  			endpointConfig.NetworkID = epConfig.NetworkID
   723  		}
   724  	}
   725  
   726  	if err := daemon.updateNetworkConfig(container, n, endpointConfig.EndpointSettings, updateSettings); err != nil {
   727  		return err
   728  	}
   729  
   730  	// TODO(thaJeztah): should this fail early if no sandbox was found?
   731  	sb, _ := daemon.netController.GetSandbox(container.ID)
   732  	createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, ipAddresses(cfg.DNS))
   733  	if err != nil {
   734  		return err
   735  	}
   736  
   737  	endpointName := strings.TrimPrefix(container.Name, "/")
   738  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   739  	if err != nil {
   740  		return err
   741  	}
   742  	defer func() {
   743  		if retErr != nil {
   744  			if err := ep.Delete(false); err != nil {
   745  				log.G(context.TODO()).Warnf("Could not rollback container connection to network %s", idOrName)
   746  			}
   747  		}
   748  	}()
   749  	container.NetworkSettings.Networks[nwName] = endpointConfig
   750  
   751  	delete(container.NetworkSettings.Networks, n.ID())
   752  
   753  	if err := daemon.updateEndpointNetworkSettings(cfg, container, n, ep); err != nil {
   754  		return err
   755  	}
   756  
   757  	if sb == nil {
   758  		sbOptions, err := daemon.buildSandboxOptions(cfg, container)
   759  		if err != nil {
   760  			return err
   761  		}
   762  		sb, err = daemon.netController.NewSandbox(container.ID, sbOptions...)
   763  		if err != nil {
   764  			return err
   765  		}
   766  
   767  		setNetworkSandbox(container, sb)
   768  	}
   769  
   770  	joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
   771  	if err != nil {
   772  		return err
   773  	}
   774  
   775  	if err := ep.Join(sb, joinOptions...); err != nil {
   776  		return err
   777  	}
   778  
   779  	if !container.Managed {
   780  		// add container name/alias to DNS
   781  		if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil {
   782  			return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err)
   783  		}
   784  	}
   785  
   786  	if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
   787  		return fmt.Errorf("Updating join info failed: %v", err)
   788  	}
   789  
   790  	container.NetworkSettings.Ports = getPortMapInfo(sb)
   791  
   792  	daemon.LogNetworkEventWithAttributes(n, events.ActionConnect, map[string]string{"container": container.ID})
   793  	networkActions.WithValues("connect").UpdateSince(start)
   794  	return nil
   795  }
   796  
   797  func updateJoinInfo(networkSettings *network.Settings, n *libnetwork.Network, ep *libnetwork.Endpoint) error {
   798  	if ep == nil {
   799  		return errors.New("invalid enppoint whhile building portmap info")
   800  	}
   801  
   802  	if networkSettings == nil {
   803  		return errors.New("invalid network settings while building port map info")
   804  	}
   805  
   806  	if len(networkSettings.Ports) == 0 {
   807  		pm, err := getEndpointPortMapInfo(ep)
   808  		if err != nil {
   809  			return err
   810  		}
   811  		networkSettings.Ports = pm
   812  	}
   813  
   814  	epInfo := ep.Info()
   815  	if epInfo == nil {
   816  		// It is not an error to get an empty endpoint info
   817  		return nil
   818  	}
   819  	if epInfo.Gateway() != nil {
   820  		networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
   821  	}
   822  	if epInfo.GatewayIPv6().To16() != nil {
   823  		networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
   824  	}
   825  	return nil
   826  }
   827  
   828  // ForceEndpointDelete deletes an endpoint from a network forcefully
   829  func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
   830  	n, err := daemon.FindNetwork(networkName)
   831  	if err != nil {
   832  		return err
   833  	}
   834  
   835  	ep, err := n.EndpointByName(name)
   836  	if err != nil {
   837  		return err
   838  	}
   839  	return ep.Delete(true)
   840  }
   841  
   842  func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n *libnetwork.Network, force bool) error {
   843  	var (
   844  		ep   *libnetwork.Endpoint
   845  		sbox *libnetwork.Sandbox
   846  	)
   847  	n.WalkEndpoints(func(current *libnetwork.Endpoint) bool {
   848  		epInfo := current.Info()
   849  		if epInfo == nil {
   850  			return false
   851  		}
   852  		if sb := epInfo.Sandbox(); sb != nil {
   853  			if sb.ContainerID() == container.ID {
   854  				ep = current
   855  				sbox = sb
   856  				return true
   857  			}
   858  		}
   859  		return false
   860  	})
   861  
   862  	if ep == nil {
   863  		if force {
   864  			var err error
   865  			ep, err = n.EndpointByName(strings.TrimPrefix(container.Name, "/"))
   866  			if err != nil {
   867  				return err
   868  			}
   869  			return ep.Delete(force)
   870  		}
   871  		return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name())
   872  	}
   873  
   874  	if err := ep.Leave(sbox); err != nil {
   875  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   876  	}
   877  
   878  	container.NetworkSettings.Ports = getPortMapInfo(sbox)
   879  
   880  	if err := ep.Delete(false); err != nil {
   881  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   882  	}
   883  
   884  	delete(container.NetworkSettings.Networks, n.Name())
   885  
   886  	daemon.tryDetachContainerFromClusterNetwork(n, container)
   887  
   888  	return nil
   889  }
   890  
   891  func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network *libnetwork.Network, container *container.Container) {
   892  	if !container.Managed && daemon.clusterProvider != nil && network.Dynamic() {
   893  		if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil {
   894  			log.G(context.TODO()).WithError(err).Warn("error detaching from network")
   895  			if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil {
   896  				log.G(context.TODO()).WithError(err).Warn("error detaching from network")
   897  			}
   898  		}
   899  	}
   900  	daemon.LogNetworkEventWithAttributes(network, events.ActionDisconnect, map[string]string{
   901  		"container": container.ID,
   902  	})
   903  }
   904  
   905  // normalizeNetMode checks whether the network mode references a network by a partial ID. In that case, it replaces the
   906  // partial ID with the full network ID.
   907  // TODO(aker): transform ID into name when the referenced network is one of the predefined.
   908  func (daemon *Daemon) normalizeNetMode(container *container.Container) error {
   909  	if container.HostConfig.NetworkMode.IsUserDefined() {
   910  		netMode := container.HostConfig.NetworkMode.NetworkName()
   911  		nw, err := daemon.FindNetwork(netMode)
   912  		if err != nil {
   913  			return fmt.Errorf("could not find a network matching network mode %s: %w", netMode, err)
   914  		}
   915  
   916  		if netMode != nw.ID() && netMode != nw.Name() {
   917  			container.HostConfig.NetworkMode = containertypes.NetworkMode(nw.ID())
   918  		}
   919  	}
   920  
   921  	return nil
   922  }
   923  
   924  func (daemon *Daemon) initializeNetworking(cfg *config.Config, container *container.Container) error {
   925  	if container.HostConfig.NetworkMode.IsContainer() {
   926  		// we need to get the hosts files from the container to join
   927  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   928  		if err != nil {
   929  			return err
   930  		}
   931  
   932  		err = daemon.initializeNetworkingPaths(container, nc)
   933  		if err != nil {
   934  			return err
   935  		}
   936  
   937  		container.Config.Hostname = nc.Config.Hostname
   938  		container.Config.Domainname = nc.Config.Domainname
   939  		return nil
   940  	}
   941  
   942  	if container.HostConfig.NetworkMode.IsHost() && container.Config.Hostname == "" {
   943  		hn, err := os.Hostname()
   944  		if err != nil {
   945  			return err
   946  		}
   947  		container.Config.Hostname = hn
   948  	}
   949  
   950  	if err := daemon.allocateNetwork(cfg, container); err != nil {
   951  		return err
   952  	}
   953  
   954  	return container.BuildHostnameFile()
   955  }
   956  
   957  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   958  	nc, err := daemon.GetContainer(connectedContainerID)
   959  	if err != nil {
   960  		return nil, err
   961  	}
   962  	if containerID == nc.ID {
   963  		return nil, fmt.Errorf("cannot join own network")
   964  	}
   965  	if !nc.IsRunning() {
   966  		return nil, errdefs.Conflict(fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID))
   967  	}
   968  	if nc.IsRestarting() {
   969  		return nil, errContainerIsRestarting(connectedContainerID)
   970  	}
   971  	return nc, nil
   972  }
   973  
   974  func (daemon *Daemon) releaseNetwork(container *container.Container) {
   975  	start := time.Now()
   976  	// If live-restore is enabled, the daemon cleans up dead containers when it starts up. In that case, the
   977  	// netController hasn't been initialized yet and so we can't proceed.
   978  	// TODO(aker): If we hit this case, the endpoint state won't be cleaned up (ie. no call to cleanOperationalData).
   979  	if daemon.netController == nil {
   980  		return
   981  	}
   982  	// If the container uses the network namespace of another container, it doesn't own it -- nothing to do here.
   983  	if container.HostConfig.NetworkMode.IsContainer() {
   984  		return
   985  	}
   986  	if container.NetworkSettings == nil {
   987  		return
   988  	}
   989  
   990  	container.NetworkSettings.Ports = nil
   991  	sid := container.NetworkSettings.SandboxID
   992  	if sid == "" {
   993  		return
   994  	}
   995  
   996  	var networks []*libnetwork.Network
   997  	for n, epSettings := range container.NetworkSettings.Networks {
   998  		if nw, err := daemon.FindNetwork(getNetworkID(n, epSettings.EndpointSettings)); err == nil {
   999  			networks = append(networks, nw)
  1000  		}
  1001  
  1002  		if epSettings.EndpointSettings == nil {
  1003  			continue
  1004  		}
  1005  
  1006  		cleanOperationalData(epSettings)
  1007  	}
  1008  
  1009  	sb, err := daemon.netController.SandboxByID(sid)
  1010  	if err != nil {
  1011  		log.G(context.TODO()).Warnf("error locating sandbox id %s: %v", sid, err)
  1012  		return
  1013  	}
  1014  
  1015  	if err := sb.Delete(); err != nil {
  1016  		log.G(context.TODO()).Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
  1017  	}
  1018  
  1019  	for _, nw := range networks {
  1020  		daemon.tryDetachContainerFromClusterNetwork(nw, container)
  1021  	}
  1022  	networkActions.WithValues("release").UpdateSince(start)
  1023  }
  1024  
  1025  func errRemovalContainer(containerID string) error {
  1026  	return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID)
  1027  }
  1028  
  1029  // ConnectToNetwork connects a container to a network
  1030  func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
  1031  	if endpointConfig == nil {
  1032  		endpointConfig = &networktypes.EndpointSettings{}
  1033  	}
  1034  	container.Lock()
  1035  	defer container.Unlock()
  1036  
  1037  	if !container.Running {
  1038  		if container.RemovalInProgress || container.Dead {
  1039  			return errRemovalContainer(container.ID)
  1040  		}
  1041  
  1042  		n, err := daemon.FindNetwork(idOrName)
  1043  		if err == nil && n != nil {
  1044  			if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil {
  1045  				return err
  1046  			}
  1047  		} else {
  1048  			container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{
  1049  				EndpointSettings: endpointConfig,
  1050  			}
  1051  		}
  1052  	} else {
  1053  		epc := &network.EndpointSettings{
  1054  			EndpointSettings: endpointConfig,
  1055  		}
  1056  		if err := daemon.connectToNetwork(&daemon.config().Config, container, idOrName, epc, true); err != nil {
  1057  			return err
  1058  		}
  1059  	}
  1060  
  1061  	return container.CheckpointTo(daemon.containersReplica)
  1062  }
  1063  
  1064  // DisconnectFromNetwork disconnects container from network n.
  1065  func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
  1066  	n, err := daemon.FindNetwork(networkName)
  1067  	container.Lock()
  1068  	defer container.Unlock()
  1069  
  1070  	if !container.Running || (err != nil && force) {
  1071  		if container.RemovalInProgress || container.Dead {
  1072  			return errRemovalContainer(container.ID)
  1073  		}
  1074  		// In case networkName is resolved we will use n.Name()
  1075  		// this will cover the case where network id is passed.
  1076  		if n != nil {
  1077  			networkName = n.Name()
  1078  		}
  1079  		if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
  1080  			return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
  1081  		}
  1082  		delete(container.NetworkSettings.Networks, networkName)
  1083  	} else if err == nil {
  1084  		if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
  1085  			return runconfig.ErrConflictHostNetwork
  1086  		}
  1087  
  1088  		if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
  1089  			return err
  1090  		}
  1091  	} else {
  1092  		return err
  1093  	}
  1094  
  1095  	if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  1096  		return err
  1097  	}
  1098  
  1099  	if n != nil {
  1100  		daemon.LogNetworkEventWithAttributes(n, events.ActionDisconnect, map[string]string{
  1101  			"container": container.ID,
  1102  		})
  1103  	}
  1104  
  1105  	return nil
  1106  }
  1107  
  1108  // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response
  1109  func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error {
  1110  	ctr, err := daemon.GetContainer(containerName)
  1111  	if err != nil {
  1112  		return err
  1113  	}
  1114  	sb, err := daemon.netController.GetSandbox(ctr.ID)
  1115  	if err != nil {
  1116  		return fmt.Errorf("failed to activate service binding for container %s: %w", containerName, err)
  1117  	}
  1118  	return sb.EnableService()
  1119  }
  1120  
  1121  // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response
  1122  func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error {
  1123  	ctr, err := daemon.GetContainer(containerName)
  1124  	if err != nil {
  1125  		return err
  1126  	}
  1127  	sb, err := daemon.netController.GetSandbox(ctr.ID)
  1128  	if err != nil {
  1129  		// If the network sandbox is not found, then there is nothing to deactivate
  1130  		log.G(context.TODO()).WithError(err).Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName)
  1131  		return nil
  1132  	}
  1133  	return sb.DisableService()
  1134  }
  1135  
  1136  func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings) string {
  1137  	// We only want to prefer NetworkID for user defined networks.
  1138  	// For systems like bridge, none, etc. the name is preferred (otherwise restart may cause issues)
  1139  	if containertypes.NetworkMode(name).IsUserDefined() && endpointSettings != nil && endpointSettings.NetworkID != "" {
  1140  		return endpointSettings.NetworkID
  1141  	}
  1142  	return name
  1143  }
  1144  
  1145  // setNetworkSandbox updates the sandbox ID and Key.
  1146  func setNetworkSandbox(c *container.Container, sb *libnetwork.Sandbox) {
  1147  	c.NetworkSettings.SandboxID = sb.ID()
  1148  	c.NetworkSettings.SandboxKey = sb.Key()
  1149  }