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