network.go
5cecd548
 package docker
 
 import (
e0e49b9a
 	"encoding/binary"
797bb6e7
 	"errors"
5039d4a2
 	"fmt"
1cbdaeba
 	"github.com/dotcloud/docker/iptables"
f6b91262
 	"github.com/dotcloud/docker/pkg/netlink"
89fb51f6
 	"github.com/dotcloud/docker/proxy"
2e69e172
 	"github.com/dotcloud/docker/utils"
799ffa17
 	"log"
5cecd548
 	"net"
799ffa17
 	"strconv"
a5fb1d6c
 	"sync"
7a94cdf8
 	"syscall"
 	"unsafe"
5cecd548
 )
 
 const (
8cf30395
 	DefaultNetworkBridge = "docker0"
49673fc4
 	DisableNetworkBridge = "none"
566ff54d
 	DefaultNetworkMtu    = 1500
1b370f9d
 	portRangeStart       = 49153
 	portRangeEnd         = 65535
7a94cdf8
 	siocBRADDBR          = 0x89a0
5cecd548
 )
 
799ffa17
 // Calculates the first and last IP addresses in an IPNet
e0e49b9a
 func networkRange(network *net.IPNet) (net.IP, net.IP) {
 	netIP := network.IP.To4()
 	firstIP := netIP.Mask(network.Mask)
 	lastIP := net.IPv4(0, 0, 0, 0).To4()
 	for i := 0; i < len(lastIP); i++ {
 		lastIP[i] = netIP[i] | ^network.Mask[i]
 	}
 	return firstIP, lastIP
 }
 
90a6e310
 // Detects overlap between one IPNet and another
 func networkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
 	firstIP, _ := networkRange(netX)
 	if netY.Contains(firstIP) {
 		return true
 	}
 	firstIP, _ = networkRange(netY)
 	if netX.Contains(firstIP) {
 		return true
 	}
 	return false
 }
 
799ffa17
 // Converts a 4 bytes IP into a 32 bit integer
6f9a67a7
 func ipToInt(ip net.IP) int32 {
 	return int32(binary.BigEndian.Uint32(ip.To4()))
e0e49b9a
 }
 
799ffa17
 // Converts 32 bit integer into a 4 bytes IP address
fd224ee5
 func intToIP(n int32) net.IP {
6f9a67a7
 	b := make([]byte, 4)
 	binary.BigEndian.PutUint32(b, uint32(n))
 	return net.IP(b)
e0e49b9a
 }
 
799ffa17
 // Given a netmask, calculates the number of available hosts
6f9a67a7
 func networkSize(mask net.IPMask) int32 {
c08f5b2b
 	m := net.IPv4Mask(0, 0, 0, 0)
e0e49b9a
 	for i := 0; i < net.IPv4len; i++ {
c08f5b2b
 		m[i] = ^mask[i]
e0e49b9a
 	}
6f9a67a7
 
 	return int32(binary.BigEndian.Uint32(m)) + 1
e0e49b9a
 }
 
494cd07f
 func checkRouteOverlaps(networks []*net.IPNet, dockerNetwork *net.IPNet) error {
 	for _, network := range networks {
 		if networkOverlaps(dockerNetwork, network) {
 			return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork, network)
aa4bf428
 		}
 	}
 	return nil
 }
 
3560c922
 func checkNameserverOverlaps(nameservers []string, dockerNetwork *net.IPNet) error {
 	if len(nameservers) > 0 {
 		for _, ns := range nameservers {
 			_, nsNetwork, err := net.ParseCIDR(ns)
 			if err != nil {
 				return err
 			}
 			if networkOverlaps(dockerNetwork, nsNetwork) {
 				return fmt.Errorf("%s overlaps nameserver %s", dockerNetwork, nsNetwork)
 			}
 		}
 	}
 	return nil
 }
 
4714f102
 // CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`,
 // and attempts to configure it with an address which doesn't conflict with any other interface on the host.
 // If it can't find an address which doesn't conflict, it will return an error.
1cbdaeba
 func CreateBridgeIface(config *DaemonConfig) error {
4714f102
 	addrs := []string{
 		// Here we don't follow the convention of using the 1st IP of the range for the gateway.
 		// This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges.
 		// In theory this shouldn't matter - in practice there's bound to be a few scripts relying
 		// on the internal addressing or other stupid things like that.
 		// The shouldn't, but hey, let's not break them unless we really have to.
9f1c9686
 		"172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23
 		"10.0.42.1/16",   // Don't even try using the entire /8, that's too intrusive
4714f102
 		"10.1.42.1/16",
 		"10.42.42.1/16",
 		"172.16.42.1/24",
 		"172.16.43.1/24",
 		"172.16.44.1/24",
 		"10.0.42.1/24",
 		"10.0.43.1/24",
 		"192.168.42.1/24",
 		"192.168.43.1/24",
 		"192.168.44.1/24",
 	}
aa4bf428
 
3560c922
 	nameservers := []string{}
 	resolvConf, _ := utils.GetResolvConf()
 	// we don't check for an error here, because we don't really care
 	// if we can't read /etc/resolv.conf. So instead we skip the append
 	// if resolvConf is nil. It either doesn't exist, or we can't read it
 	// for some reason.
 	if resolvConf != nil {
 		nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...)
 	}
 
aa4bf428
 	var ifaceAddr string
a68d7f3d
 	if len(config.BridgeIp) != 0 {
 		_, _, err := net.ParseCIDR(config.BridgeIp)
aa4bf428
 		if err != nil {
 			return err
 		}
a68d7f3d
 		ifaceAddr = config.BridgeIp
 	} else {
 		for _, addr := range addrs {
 			_, dockerNetwork, err := net.ParseCIDR(addr)
 			if err != nil {
 				return err
 			}
 			routes, err := netlink.NetworkGetRoutes()
 			if err != nil {
 				return err
 			}
 			if err := checkRouteOverlaps(routes, dockerNetwork); err == nil {
 				if err := checkNameserverOverlaps(nameservers, dockerNetwork); err == nil {
 					ifaceAddr = addr
 					break
 				}
 			} else {
 				utils.Debugf("%s: %s", addr, err)
3560c922
 			}
aa4bf428
 		}
 	}
 	if ifaceAddr == "" {
1cbdaeba
 		return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", config.BridgeIface, config.BridgeIface)
aa4bf428
 	}
1cbdaeba
 	utils.Debugf("Creating bridge %s with network %s", config.BridgeIface, ifaceAddr)
aa4bf428
 
7a94cdf8
 	if err := createBridgeIface(config.BridgeIface); err != nil {
 		return err
aa4bf428
 	}
494cd07f
 	iface, err := net.InterfaceByName(config.BridgeIface)
 	if err != nil {
 		return err
 	}
 	ipAddr, ipNet, err := net.ParseCIDR(ifaceAddr)
 	if err != nil {
 		return err
 	}
 	if netlink.NetworkLinkAddIp(iface, ipAddr, ipNet); err != nil {
 		return fmt.Errorf("Unable to add private network: %s", err)
aa4bf428
 	}
494cd07f
 	if err := netlink.NetworkLinkUp(iface); err != nil {
 		return fmt.Errorf("Unable to start network bridge: %s", err)
aa4bf428
 	}
ce965b8c
 
aa4bf428
 	return nil
 }
 
7a94cdf8
 // Create the actual bridge device.  This is more backward-compatible than
 // netlink.NetworkLinkAdd and works on RHEL 6.
 func createBridgeIface(name string) error {
 	s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
 	if err != nil {
a530b8d9
 		utils.Debugf("Bridge socket creation failed IPv6 probably not enabled: %v", err)
 		s, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_IP)
 		if err != nil {
 			return fmt.Errorf("Error creating bridge creation socket: %s", err)
 		}
7a94cdf8
 	}
 	defer syscall.Close(s)
 
 	nameBytePtr, err := syscall.BytePtrFromString(name)
 	if err != nil {
 		return fmt.Errorf("Error converting bridge name %s to byte array: %s", name, err)
 	}
 
 	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), siocBRADDBR, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
 		return fmt.Errorf("Error creating bridge: %s", err)
 	}
 	return nil
 }
 
799ffa17
 // Return the IPv4 address of a network interface
c08f5b2b
 func getIfaceAddr(name string) (net.Addr, error) {
5039d4a2
 	iface, err := net.InterfaceByName(name)
 	if err != nil {
 		return nil, err
 	}
 	addrs, err := iface.Addrs()
 	if err != nil {
 		return nil, err
 	}
 	var addrs4 []net.Addr
 	for _, addr := range addrs {
 		ip := (addr.(*net.IPNet)).IP
 		if ip4 := ip.To4(); len(ip4) == net.IPv4len {
 			addrs4 = append(addrs4, addr)
 		}
 	}
 	switch {
 	case len(addrs4) == 0:
799ffa17
 		return nil, fmt.Errorf("Interface %v has no IP addresses", name)
5039d4a2
 	case len(addrs4) > 1:
3aefed2d
 		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
 			name, (addrs4[0].(*net.IPNet)).IP)
5039d4a2
 	}
 	return addrs4[0], nil
 }
 
799ffa17
 // Port mapper takes care of mapping external ports to containers by setting
 // up iptables rules.
 // It keeps track of all mappings and is able to unmap at will
 type PortMapper struct {
1cb1e086
 	tcpMapping map[string]*net.TCPAddr
 	tcpProxies map[string]proxy.Proxy
 	udpMapping map[string]*net.UDPAddr
 	udpProxies map[string]proxy.Proxy
799ffa17
 
1cb1e086
 	iptables         *iptables.Chain
 	defaultIp        net.IP
 	proxyFactoryFunc func(net.Addr, net.Addr) (proxy.Proxy, error)
799ffa17
 }
 
1cbdaeba
 func (mapper *PortMapper) Map(ip net.IP, port int, backendAddr net.Addr) error {
1cb1e086
 	mapKey := (&net.TCPAddr{Port: port, IP: ip}).String()
 	if _, exists := mapper.tcpProxies[mapKey]; exists {
 		return fmt.Errorf("Port %s is already in use", mapKey)
 	}
 
fac0d87d
 	if _, isTCP := backendAddr.(*net.TCPAddr); isTCP {
 		backendPort := backendAddr.(*net.TCPAddr).Port
 		backendIP := backendAddr.(*net.TCPAddr).IP
1cbdaeba
 		if mapper.iptables != nil {
 			if err := mapper.iptables.Forward(iptables.Add, ip, port, "tcp", backendIP.String(), backendPort); err != nil {
 				return err
 			}
fac0d87d
 		}
1cb1e086
 		mapper.tcpMapping[mapKey] = backendAddr.(*net.TCPAddr)
 		proxy, err := mapper.proxyFactoryFunc(&net.TCPAddr{IP: ip, Port: port}, backendAddr)
930e9a7e
 		if err != nil {
1cbdaeba
 			mapper.Unmap(ip, port, "tcp")
930e9a7e
 			return err
 		}
1cb1e086
 		mapper.tcpProxies[mapKey] = proxy
fac0d87d
 		go proxy.Run()
 	} else {
 		backendPort := backendAddr.(*net.UDPAddr).Port
 		backendIP := backendAddr.(*net.UDPAddr).IP
1cbdaeba
 		if mapper.iptables != nil {
 			if err := mapper.iptables.Forward(iptables.Add, ip, port, "udp", backendIP.String(), backendPort); err != nil {
 				return err
 			}
fac0d87d
 		}
1cb1e086
 		mapper.udpMapping[mapKey] = backendAddr.(*net.UDPAddr)
 		proxy, err := mapper.proxyFactoryFunc(&net.UDPAddr{IP: ip, Port: port}, backendAddr)
930e9a7e
 		if err != nil {
1cbdaeba
 			mapper.Unmap(ip, port, "udp")
fac0d87d
 			return err
930e9a7e
 		}
1cb1e086
 		mapper.udpProxies[mapKey] = proxy
fac0d87d
 		go proxy.Run()
930e9a7e
 	}
fac0d87d
 	return nil
930e9a7e
 }
 
1cbdaeba
 func (mapper *PortMapper) Unmap(ip net.IP, port int, proto string) error {
1cb1e086
 	mapKey := (&net.TCPAddr{Port: port, IP: ip}).String()
fac0d87d
 	if proto == "tcp" {
1cb1e086
 		backendAddr, ok := mapper.tcpMapping[mapKey]
fac0d87d
 		if !ok {
1cb1e086
 			return fmt.Errorf("Port tcp/%s is not mapped", mapKey)
fac0d87d
 		}
1cb1e086
 		if proxy, exists := mapper.tcpProxies[mapKey]; exists {
fac0d87d
 			proxy.Close()
1cb1e086
 			delete(mapper.tcpProxies, mapKey)
fac0d87d
 		}
1cbdaeba
 		if mapper.iptables != nil {
 			if err := mapper.iptables.Forward(iptables.Delete, ip, port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
 				return err
 			}
fac0d87d
 		}
1cb1e086
 		delete(mapper.tcpMapping, mapKey)
fac0d87d
 	} else {
1cb1e086
 		backendAddr, ok := mapper.udpMapping[mapKey]
fac0d87d
 		if !ok {
1cb1e086
 			return fmt.Errorf("Port udp/%s is not mapped", mapKey)
fac0d87d
 		}
1cb1e086
 		if proxy, exists := mapper.udpProxies[mapKey]; exists {
fac0d87d
 			proxy.Close()
1cb1e086
 			delete(mapper.udpProxies, mapKey)
fac0d87d
 		}
1cbdaeba
 		if mapper.iptables != nil {
 			if err := mapper.iptables.Forward(iptables.Delete, ip, port, proto, backendAddr.IP.String(), backendAddr.Port); err != nil {
 				return err
 			}
fac0d87d
 		}
1cb1e086
 		delete(mapper.udpMapping, mapKey)
e0e49b9a
 	}
799ffa17
 	return nil
 }
 
1cbdaeba
 func newPortMapper(config *DaemonConfig) (*PortMapper, error) {
 	// We can always try removing the iptables
 	if err := iptables.RemoveExistingChain("DOCKER"); err != nil {
c08f5b2b
 		return nil, err
5cecd548
 	}
1cbdaeba
 	var chain *iptables.Chain
 	if config.EnableIptables {
 		var err error
 		chain, err = iptables.NewChain("DOCKER", config.BridgeIface)
 		if err != nil {
 			return nil, fmt.Errorf("Failed to create DOCKER chain: %s", err)
 		}
 	}
 
 	mapper := &PortMapper{
1cb1e086
 		tcpMapping:       make(map[string]*net.TCPAddr),
 		tcpProxies:       make(map[string]proxy.Proxy),
 		udpMapping:       make(map[string]*net.UDPAddr),
 		udpProxies:       make(map[string]proxy.Proxy),
 		iptables:         chain,
 		defaultIp:        config.DefaultIp,
 		proxyFactoryFunc: proxy.NewProxy,
799ffa17
 	}
 	return mapper, nil
5cecd548
 }
797bb6e7
 
9b2a5964
 // Port allocator: Automatically allocate and release networking ports
799ffa17
 type PortAllocator struct {
1cf9c80e
 	sync.Mutex
1cb1e086
 	inUse    map[string]struct{}
9107565d
 	fountain chan int
 	quit     chan bool
797bb6e7
 }
 
a5fb1d6c
 func (alloc *PortAllocator) runFountain() {
 	for {
 		for port := portRangeStart; port < portRangeEnd; port++ {
9107565d
 			select {
 			case alloc.fountain <- port:
 			case quit := <-alloc.quit:
 				if quit {
 					return
 				}
 			}
a5fb1d6c
 		}
797bb6e7
 	}
 }
 
a5fb1d6c
 // FIXME: Release can no longer fail, change its prototype to reflect that.
1cb1e086
 func (alloc *PortAllocator) Release(addr net.IP, port int) error {
 	mapKey := (&net.TCPAddr{Port: port, IP: addr}).String()
2e69e172
 	utils.Debugf("Releasing %d", port)
1cf9c80e
 	alloc.Lock()
1cb1e086
 	delete(alloc.inUse, mapKey)
1cf9c80e
 	alloc.Unlock()
a5fb1d6c
 	return nil
 }
 
1cb1e086
 func (alloc *PortAllocator) Acquire(addr net.IP, port int) (int, error) {
 	mapKey := (&net.TCPAddr{Port: port, IP: addr}).String()
 	utils.Debugf("Acquiring %s", mapKey)
a5fb1d6c
 	if port == 0 {
 		// Allocate a port from the fountain
 		for port := range alloc.fountain {
1cb1e086
 			if _, err := alloc.Acquire(addr, port); err == nil {
a5fb1d6c
 				return port, nil
 			}
 		}
 		return -1, fmt.Errorf("Port generator ended unexpectedly")
797bb6e7
 	}
1cf9c80e
 	alloc.Lock()
 	defer alloc.Unlock()
1cb1e086
 	if _, inUse := alloc.inUse[mapKey]; inUse {
a5fb1d6c
 		return -1, fmt.Errorf("Port already in use: %d", port)
 	}
1cb1e086
 	alloc.inUse[mapKey] = struct{}{}
a5fb1d6c
 	return port, nil
797bb6e7
 }
 
9107565d
 func (alloc *PortAllocator) Close() error {
 	alloc.quit <- true
 	close(alloc.quit)
 	close(alloc.fountain)
 	return nil
 }
 
a5fb1d6c
 func newPortAllocator() (*PortAllocator, error) {
 	allocator := &PortAllocator{
1cb1e086
 		inUse:    make(map[string]struct{}),
d32f1846
 		fountain: make(chan int),
9107565d
 		quit:     make(chan bool),
a5fb1d6c
 	}
 	go allocator.runFountain()
799ffa17
 	return allocator, nil
 }
 
9b2a5964
 // IP allocator: Automatically allocate and release networking ports
799ffa17
 type IPAllocator struct {
6f9a67a7
 	network       *net.IPNet
 	queueAlloc    chan allocatedIP
 	queueReleased chan net.IP
 	inUse         map[int32]struct{}
9107565d
 	quit          chan bool
6f9a67a7
 }
 
 type allocatedIP struct {
 	ip  net.IP
 	err error
799ffa17
 }
 
6f9a67a7
 func (alloc *IPAllocator) run() {
799ffa17
 	firstIP, _ := networkRange(alloc.network)
6f9a67a7
 	ipNum := ipToInt(firstIP)
 	ownIP := ipToInt(alloc.network.IP)
 	size := networkSize(alloc.network.Mask)
 
 	pos := int32(1)
 	max := size - 2 // -1 for the broadcast address, -1 for the gateway address
 	for {
 		var (
 			newNum int32
 			inUse  bool
 		)
 
 		// Find first unused IP, give up after one whole round
 		for attempt := int32(0); attempt < max; attempt++ {
 			newNum = ipNum + pos
 
 			pos = pos%max + 1
 
 			// The network's IP is never okay to use
 			if newNum == ownIP {
 				continue
 			}
 
 			if _, inUse = alloc.inUse[newNum]; !inUse {
 				// We found an unused IP
 				break
 			}
797bb6e7
 		}
6f9a67a7
 
fd224ee5
 		ip := allocatedIP{ip: intToIP(newNum)}
6f9a67a7
 		if inUse {
 			ip.err = errors.New("No unallocated IP available")
797bb6e7
 		}
6f9a67a7
 
 		select {
9107565d
 		case quit := <-alloc.quit:
 			if quit {
 				return
 			}
6f9a67a7
 		case alloc.queueAlloc <- ip:
 			alloc.inUse[newNum] = struct{}{}
 		case released := <-alloc.queueReleased:
 			r := ipToInt(released)
 			delete(alloc.inUse, r)
 
 			if inUse {
 				// If we couldn't allocate a new IP, the released one
 				// will be the only free one now, so instantly use it
 				// next time
 				pos = r - ipNum
 			} else {
 				// Use same IP as last time
 				if pos == 1 {
 					pos = max
 				} else {
 					pos--
 				}
 			}
797bb6e7
 		}
799ffa17
 	}
 }
 
 func (alloc *IPAllocator) Acquire() (net.IP, error) {
6f9a67a7
 	ip := <-alloc.queueAlloc
 	return ip.ip, ip.err
799ffa17
 }
 
6f9a67a7
 func (alloc *IPAllocator) Release(ip net.IP) {
 	alloc.queueReleased <- ip
797bb6e7
 }
 
9107565d
 func (alloc *IPAllocator) Close() error {
 	alloc.quit <- true
 	close(alloc.quit)
 	close(alloc.queueAlloc)
 	close(alloc.queueReleased)
 	return nil
 }
 
6f9a67a7
 func newIPAllocator(network *net.IPNet) *IPAllocator {
799ffa17
 	alloc := &IPAllocator{
6f9a67a7
 		network:       network,
 		queueAlloc:    make(chan allocatedIP),
 		queueReleased: make(chan net.IP),
 		inUse:         make(map[int32]struct{}),
9107565d
 		quit:          make(chan bool),
799ffa17
 	}
6f9a67a7
 
 	go alloc.run()
 
 	return alloc
799ffa17
 }
 
 // Network interface represents the networking stack of a container
 type NetworkInterface struct {
 	IPNet   net.IPNet
 	Gateway net.IP
 
 	manager  *NetworkManager
fac0d87d
 	extPorts []*Nat
49673fc4
 	disabled bool
799ffa17
 }
 
1cbdaeba
 // Allocate an external port and map it to the interface
 func (iface *NetworkInterface) AllocatePort(port Port, binding PortBinding) (*Nat, error) {
49673fc4
 
 	if iface.disabled {
 		return nil, fmt.Errorf("Trying to allocate port for interface %v, which is disabled", iface) // FIXME
 	}
 
1cbdaeba
 	ip := iface.manager.portMapper.defaultIp
 
 	if binding.HostIp != "" {
 		ip = net.ParseIP(binding.HostIp)
 	} else {
 		binding.HostIp = ip.String()
 	}
 
 	nat := &Nat{
 		Port:    port,
 		Binding: binding,
 	}
 
 	containerPort, err := parsePort(port.Port())
799ffa17
 	if err != nil {
2aad4a34
 		return nil, err
 	}
fac0d87d
 
1cbdaeba
 	hostPort, _ := parsePort(nat.Binding.HostPort)
 
 	if nat.Port.Proto() == "tcp" {
1cb1e086
 		extPort, err := iface.manager.tcpPortAllocator.Acquire(ip, hostPort)
fac0d87d
 		if err != nil {
 			return nil, err
 		}
1cbdaeba
 
 		backend := &net.TCPAddr{IP: iface.IPNet.IP, Port: containerPort}
 		if err := iface.manager.portMapper.Map(ip, extPort, backend); err != nil {
1cb1e086
 			iface.manager.tcpPortAllocator.Release(ip, extPort)
fac0d87d
 			return nil, err
 		}
1cbdaeba
 		nat.Binding.HostPort = strconv.Itoa(extPort)
fac0d87d
 	} else {
1cb1e086
 		extPort, err := iface.manager.udpPortAllocator.Acquire(ip, hostPort)
fac0d87d
 		if err != nil {
 			return nil, err
 		}
1cbdaeba
 		backend := &net.UDPAddr{IP: iface.IPNet.IP, Port: containerPort}
 		if err := iface.manager.portMapper.Map(ip, extPort, backend); err != nil {
1cb1e086
 			iface.manager.udpPortAllocator.Release(ip, extPort)
fac0d87d
 			return nil, err
 		}
1cbdaeba
 		nat.Binding.HostPort = strconv.Itoa(extPort)
2aad4a34
 	}
fac0d87d
 	iface.extPorts = append(iface.extPorts, nat)
 
2aad4a34
 	return nat, nil
 }
 
 type Nat struct {
1cbdaeba
 	Port    Port
 	Binding PortBinding
2aad4a34
 }
 
1cbdaeba
 func (n *Nat) String() string {
a6c9a332
 	return fmt.Sprintf("%s:%s:%s/%s", n.Binding.HostIp, n.Binding.HostPort, n.Port.Port(), n.Port.Proto())
799ffa17
 }
 
 // Release: Network cleanup - release all resources
6f9a67a7
 func (iface *NetworkInterface) Release() {
49673fc4
 	if iface.disabled {
 		return
 	}
 
fac0d87d
 	for _, nat := range iface.extPorts {
1cbdaeba
 		hostPort, err := parsePort(nat.Binding.HostPort)
 		if err != nil {
 			log.Printf("Unable to get host port: %s", err)
 			continue
 		}
 		ip := net.ParseIP(nat.Binding.HostIp)
1cb1e086
 		utils.Debugf("Unmaping %s/%s:%s", nat.Port.Proto, ip.String(), nat.Binding.HostPort)
1cbdaeba
 		if err := iface.manager.portMapper.Unmap(ip, hostPort, nat.Port.Proto()); err != nil {
 			log.Printf("Unable to unmap port %s: %s", nat, err)
799ffa17
 		}
1cb1e086
 
1cbdaeba
 		if nat.Port.Proto() == "tcp" {
1cb1e086
 			if err := iface.manager.tcpPortAllocator.Release(ip, hostPort); err != nil {
1cbdaeba
 				log.Printf("Unable to release port %s", nat)
fac0d87d
 			}
1cb1e086
 		} else if nat.Port.Proto() == "udp" {
7d2e851d
 			if err := iface.manager.udpPortAllocator.Release(ip, hostPort); err != nil {
1cb1e086
 				log.Printf("Unable to release port %s: %s", nat, err)
 			}
799ffa17
 		}
 	}
6f9a67a7
 
 	iface.manager.ipAllocator.Release(iface.IPNet.IP)
799ffa17
 }
 
 // Network Manager manages a set of network interfaces
 // Only *one* manager per host machine should be used
 type NetworkManager struct {
 	bridgeIface   string
 	bridgeNetwork *net.IPNet
 
fac0d87d
 	ipAllocator      *IPAllocator
 	tcpPortAllocator *PortAllocator
 	udpPortAllocator *PortAllocator
 	portMapper       *PortMapper
49673fc4
 
 	disabled bool
799ffa17
 }
 
 // Allocate a network interface
 func (manager *NetworkManager) Allocate() (*NetworkInterface, error) {
49673fc4
 
 	if manager.disabled {
 		return &NetworkInterface{disabled: true}, nil
 	}
 
2f6ce27f
 	var ip net.IP
 	var err error
 
 	ip, err = manager.ipAllocator.Acquire()
797bb6e7
 	if err != nil {
c08f5b2b
 		return nil, err
797bb6e7
 	}
6756e786
 	// avoid duplicate IP
2f6ce27f
 	ipNum := ipToInt(ip)
 	firstIP := manager.ipAllocator.network.IP.To4().Mask(manager.ipAllocator.network.Mask)
 	firstIPNum := ipToInt(firstIP) + 1
 
 	if firstIPNum == ipNum {
 		ip, err = manager.ipAllocator.Acquire()
 		if err != nil {
 			return nil, err
 		}
 	}
 
c08f5b2b
 	iface := &NetworkInterface{
ab99e925
 		IPNet:   net.IPNet{IP: ip, Mask: manager.bridgeNetwork.Mask},
799ffa17
 		Gateway: manager.bridgeNetwork.IP,
 		manager: manager,
c08f5b2b
 	}
 	return iface, nil
 }
 
9107565d
 func (manager *NetworkManager) Close() error {
ef14aaf6
 	if manager.disabled {
 		return nil
 	}
9107565d
 	err1 := manager.tcpPortAllocator.Close()
 	err2 := manager.udpPortAllocator.Close()
 	err3 := manager.ipAllocator.Close()
 	if err1 != nil {
 		return err1
 	}
 	if err2 != nil {
 		return err2
 	}
 	return err3
 }
 
1cbdaeba
 func newNetworkManager(config *DaemonConfig) (*NetworkManager, error) {
 	if config.BridgeIface == DisableNetworkBridge {
49673fc4
 		manager := &NetworkManager{
 			disabled: true,
 		}
 		return manager, nil
 	}
 
1cbdaeba
 	addr, err := getIfaceAddr(config.BridgeIface)
799ffa17
 	if err != nil {
aa4bf428
 		// If the iface is not found, try to create it
1cbdaeba
 		if err := CreateBridgeIface(config); err != nil {
aa4bf428
 			return nil, err
 		}
1cbdaeba
 		addr, err = getIfaceAddr(config.BridgeIface)
aa4bf428
 		if err != nil {
 			return nil, err
 		}
799ffa17
 	}
 	network := addr.(*net.IPNet)
 
94e5081b
 	// Configure iptables for link support
 	if config.EnableIptables {
0ff9bc1b
 
 		// Enable NAT
 		natArgs := []string{"POSTROUTING", "-t", "nat", "-s", addr.String(), "!", "-d", addr.String(), "-j", "MASQUERADE"}
 
 		if !iptables.Exists(natArgs...) {
 			if output, err := iptables.Raw(append([]string{"-A"}, natArgs...)...); err != nil {
 				return nil, fmt.Errorf("Unable to enable network bridge NAT: %s", err)
 			} else if len(output) != 0 {
 				return nil, fmt.Errorf("Error iptables postrouting: %s", output)
 			}
 		}
 
 		// Accept incoming packets for existing connections
 		existingArgs := []string{"FORWARD", "-o", config.BridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}
 
 		if !iptables.Exists(existingArgs...) {
 			if output, err := iptables.Raw(append([]string{"-I"}, existingArgs...)...); err != nil {
 				return nil, fmt.Errorf("Unable to allow incoming packets: %s", err)
 			} else if len(output) != 0 {
 				return nil, fmt.Errorf("Error iptables allow incoming: %s", output)
 			}
 		}
 
 		// Accept all non-intercontainer outgoing packets
 		outgoingArgs := []string{"FORWARD", "-i", config.BridgeIface, "!", "-o", config.BridgeIface, "-j", "ACCEPT"}
 
 		if !iptables.Exists(outgoingArgs...) {
 			if output, err := iptables.Raw(append([]string{"-I"}, outgoingArgs...)...); err != nil {
 				return nil, fmt.Errorf("Unable to allow outgoing packets: %s", err)
 			} else if len(output) != 0 {
 				return nil, fmt.Errorf("Error iptables allow outgoing: %s", output)
 			}
 		}
 
ec4657b2
 		args := []string{"FORWARD", "-i", config.BridgeIface, "-o", config.BridgeIface, "-j"}
 		acceptArgs := append(args, "ACCEPT")
 		dropArgs := append(args, "DROP")
94e5081b
 
 		if !config.InterContainerCommunication {
ec4657b2
 			iptables.Raw(append([]string{"-D"}, acceptArgs...)...)
 			if !iptables.Exists(dropArgs...) {
94e5081b
 				utils.Debugf("Disable inter-container communication")
ec4657b2
 				if output, err := iptables.Raw(append([]string{"-I"}, dropArgs...)...); err != nil {
94e5081b
 					return nil, fmt.Errorf("Unable to prevent intercontainer communication: %s", err)
ff8a4ba0
 				} else if len(output) != 0 {
ec4657b2
 					return nil, fmt.Errorf("Error disabling intercontainer communication: %s", output)
94e5081b
 				}
 			}
 		} else {
ec4657b2
 			iptables.Raw(append([]string{"-D"}, dropArgs...)...)
 			if !iptables.Exists(acceptArgs...) {
 				utils.Debugf("Enable inter-container communication")
 				if output, err := iptables.Raw(append([]string{"-I"}, acceptArgs...)...); err != nil {
 					return nil, fmt.Errorf("Unable to allow intercontainer communication: %s", err)
 				} else if len(output) != 0 {
 					return nil, fmt.Errorf("Error enabling intercontainer communication: %s", output)
 				}
 			}
94e5081b
 		}
 	}
 
6f9a67a7
 	ipAllocator := newIPAllocator(network)
799ffa17
 
fac0d87d
 	tcpPortAllocator, err := newPortAllocator()
 	if err != nil {
 		return nil, err
 	}
1cb1e086
 
fac0d87d
 	udpPortAllocator, err := newPortAllocator()
799ffa17
 	if err != nil {
 		return nil, err
 	}
 
1cbdaeba
 	portMapper, err := newPortMapper(config)
37122552
 	if err != nil {
 		return nil, err
 	}
799ffa17
 
 	manager := &NetworkManager{
1cbdaeba
 		bridgeIface:      config.BridgeIface,
fac0d87d
 		bridgeNetwork:    network,
 		ipAllocator:      ipAllocator,
 		tcpPortAllocator: tcpPortAllocator,
 		udpPortAllocator: udpPortAllocator,
 		portMapper:       portMapper,
799ffa17
 	}
9107565d
 
799ffa17
 	return manager, nil
797bb6e7
 }