Pārlūkot izejas kodu

Merge pull request #41604 from arkodg/bump-libnetwork-ipv6nat

Vendor in Libnetwork changes
Sebastiaan van Stijn 4 gadi atpakaļ
vecāks
revīzija
c90671b4cd

+ 1 - 1
hack/dockerfile/install/proxy.installer

@@ -3,7 +3,7 @@
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # updating the binary version, consider updating github.com/docker/libnetwork
 # updating the binary version, consider updating github.com/docker/libnetwork
 # in vendor.conf accordingly
 # in vendor.conf accordingly
-: "${LIBNETWORK_COMMIT:=d0951081b35fa4216fc4f0064bf065beeb55a74b}"
+: "${LIBNETWORK_COMMIT:=d511c60c5c23e6753631244f271a1ec6097254a5}"
 
 
 install_proxy() {
 install_proxy() {
 	case "$1" in
 	case "$1" in

+ 3 - 2
integration-cli/docker_cli_daemon_test.go

@@ -945,12 +945,13 @@ func (s *DockerDaemonSuite) TestDaemonLinksIpTablesRulesWhenLinkAndUnlink(c *tes
 
 
 	sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
 	sourceRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
 	destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
 	destinationRule := []string{"-i", bridgeName, "-o", bridgeName, "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
-	if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
+	iptable := iptables.GetIptable(iptables.IPv4)
+	if !iptable.Exists("filter", "DOCKER", sourceRule...) || !iptable.Exists("filter", "DOCKER", destinationRule...) {
 		c.Fatal("Iptables rules not found")
 		c.Fatal("Iptables rules not found")
 	}
 	}
 
 
 	s.d.Cmd("rm", "--link", "parent/http")
 	s.d.Cmd("rm", "--link", "parent/http")
-	if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
+	if iptable.Exists("filter", "DOCKER", sourceRule...) || iptable.Exists("filter", "DOCKER", destinationRule...) {
 		c.Fatal("Iptables rules should be removed when unlink")
 		c.Fatal("Iptables rules should be removed when unlink")
 	}
 	}
 
 

+ 1 - 1
vendor.conf

@@ -46,7 +46,7 @@ github.com/grpc-ecosystem/go-grpc-middleware        3c51f7f332123e8be5a157c0802a
 # libnetwork
 # libnetwork
 
 
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly
-github.com/docker/libnetwork                        d0951081b35fa4216fc4f0064bf065beeb55a74b
+github.com/docker/libnetwork                        d511c60c5c23e6753631244f271a1ec6097254a5 
 github.com/docker/go-events                         e31b211e4f1cd09aa76fe4ac244571fab96ae47f
 github.com/docker/go-events                         e31b211e4f1cd09aa76fe4ac244571fab96ae47f
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-radix                           e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec
 github.com/armon/go-metrics                         eb0af217e5e9747e41dd5303755356b62d28e3ec

+ 87 - 30
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go

@@ -57,6 +57,7 @@ type iptablesCleanFuncs []iptableCleanFunc
 type configuration struct {
 type configuration struct {
 	EnableIPForwarding  bool
 	EnableIPForwarding  bool
 	EnableIPTables      bool
 	EnableIPTables      bool
+	EnableIP6Tables     bool
 	EnableUserlandProxy bool
 	EnableUserlandProxy bool
 	UserlandProxyPath   string
 	UserlandProxyPath   string
 }
 }
@@ -133,22 +134,27 @@ type bridgeNetwork struct {
 	config        *networkConfiguration
 	config        *networkConfiguration
 	endpoints     map[string]*bridgeEndpoint // key: endpoint id
 	endpoints     map[string]*bridgeEndpoint // key: endpoint id
 	portMapper    *portmapper.PortMapper
 	portMapper    *portmapper.PortMapper
+	portMapperV6  *portmapper.PortMapper
 	driver        *driver // The network's driver
 	driver        *driver // The network's driver
 	iptCleanFuncs iptablesCleanFuncs
 	iptCleanFuncs iptablesCleanFuncs
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
 type driver struct {
 type driver struct {
-	config          *configuration
-	network         *bridgeNetwork
-	natChain        *iptables.ChainInfo
-	filterChain     *iptables.ChainInfo
-	isolationChain1 *iptables.ChainInfo
-	isolationChain2 *iptables.ChainInfo
-	networks        map[string]*bridgeNetwork
-	store           datastore.DataStore
-	nlh             *netlink.Handle
-	configNetwork   sync.Mutex
+	config            *configuration
+	network           *bridgeNetwork
+	natChain          *iptables.ChainInfo
+	filterChain       *iptables.ChainInfo
+	isolationChain1   *iptables.ChainInfo
+	isolationChain2   *iptables.ChainInfo
+	natChainV6        *iptables.ChainInfo
+	filterChainV6     *iptables.ChainInfo
+	isolationChain1V6 *iptables.ChainInfo
+	isolationChain2V6 *iptables.ChainInfo
+	networks          map[string]*bridgeNetwork
+	store             datastore.DataStore
+	nlh               *netlink.Handle
+	configNetwork     sync.Mutex
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
@@ -277,7 +283,7 @@ func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) {
 	n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
 	n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
 }
 }
 
 
-func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
+func (n *bridgeNetwork) getDriverChains(version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
 	n.Lock()
 	n.Lock()
 	defer n.Unlock()
 	defer n.Unlock()
 
 
@@ -285,6 +291,10 @@ func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainI
 		return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
 		return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
 	}
 	}
 
 
+	if version == iptables.IPv6 {
+		return n.driver.natChainV6, n.driver.filterChainV6, n.driver.isolationChain1V6, n.driver.isolationChain2V6, nil
+	}
+
 	return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
 	return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
 }
 }
 
 
@@ -323,17 +333,31 @@ func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) err
 	}
 	}
 
 
 	// Install the rules to isolate this network against each of the other networks
 	// Install the rules to isolate this network against each of the other networks
-	return setINC(thisConfig.BridgeName, enable)
+	if n.driver.config.EnableIP6Tables {
+		err := setINC(iptables.IPv6, thisConfig.BridgeName, enable)
+		if err != nil {
+			return err
+		}
+	}
+
+	if n.driver.config.EnableIPTables {
+		return setINC(iptables.IPv4, thisConfig.BridgeName, enable)
+	}
+	return nil
 }
 }
 
 
 func (d *driver) configure(option map[string]interface{}) error {
 func (d *driver) configure(option map[string]interface{}) error {
 	var (
 	var (
-		config          *configuration
-		err             error
-		natChain        *iptables.ChainInfo
-		filterChain     *iptables.ChainInfo
-		isolationChain1 *iptables.ChainInfo
-		isolationChain2 *iptables.ChainInfo
+		config            *configuration
+		err               error
+		natChain          *iptables.ChainInfo
+		filterChain       *iptables.ChainInfo
+		isolationChain1   *iptables.ChainInfo
+		isolationChain2   *iptables.ChainInfo
+		natChainV6        *iptables.ChainInfo
+		filterChainV6     *iptables.ChainInfo
+		isolationChain1V6 *iptables.ChainInfo
+		isolationChain2V6 *iptables.ChainInfo
 	)
 	)
 
 
 	genericData, ok := option[netlabel.GenericData]
 	genericData, ok := option[netlabel.GenericData]
@@ -354,23 +378,46 @@ func (d *driver) configure(option map[string]interface{}) error {
 		return &ErrInvalidDriverConfig{}
 		return &ErrInvalidDriverConfig{}
 	}
 	}
 
 
-	if config.EnableIPTables {
+	if config.EnableIPTables || config.EnableIP6Tables {
 		if _, err := os.Stat("/proc/sys/net/bridge"); err != nil {
 		if _, err := os.Stat("/proc/sys/net/bridge"); err != nil {
 			if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil {
 			if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil {
 				logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
 				logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
 			}
 			}
 		}
 		}
-		removeIPChains()
-		natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config)
+	}
+
+	if config.EnableIPTables {
+		removeIPChains(iptables.IPv4)
+
+		natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config, iptables.IPv4)
+		if err != nil {
+			return err
+		}
+
+		// Make sure on firewall reload, first thing being re-played is chains creation
+		iptables.OnReloaded(func() {
+			logrus.Debugf("Recreating iptables chains on firewall reload")
+			setupIPChains(config, iptables.IPv4)
+		})
+	}
+
+	if config.EnableIP6Tables {
+		removeIPChains(iptables.IPv6)
+
+		natChainV6, filterChainV6, isolationChain1V6, isolationChain2V6, err = setupIPChains(config, iptables.IPv6)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
+
 		// Make sure on firewall reload, first thing being re-played is chains creation
 		// Make sure on firewall reload, first thing being re-played is chains creation
-		iptables.OnReloaded(func() { logrus.Debugf("Recreating iptables chains on firewall reload"); setupIPChains(config) })
+		iptables.OnReloaded(func() {
+			logrus.Debugf("Recreating ip6tables chains on firewall reload")
+			setupIPChains(config, iptables.IPv6)
+		})
 	}
 	}
 
 
 	if config.EnableIPForwarding {
 	if config.EnableIPForwarding {
-		err = setupIPForwarding(config.EnableIPTables)
+		err = setupIPForwarding(config.EnableIPTables, config.EnableIP6Tables)
 		if err != nil {
 		if err != nil {
 			logrus.Warn(err)
 			logrus.Warn(err)
 			return err
 			return err
@@ -382,6 +429,10 @@ func (d *driver) configure(option map[string]interface{}) error {
 	d.filterChain = filterChain
 	d.filterChain = filterChain
 	d.isolationChain1 = isolationChain1
 	d.isolationChain1 = isolationChain1
 	d.isolationChain2 = isolationChain2
 	d.isolationChain2 = isolationChain2
+	d.natChainV6 = natChainV6
+	d.filterChainV6 = filterChainV6
+	d.isolationChain1V6 = isolationChain1V6
+	d.isolationChain2V6 = isolationChain2V6
 	d.config = config
 	d.config = config
 	d.Unlock()
 	d.Unlock()
 
 
@@ -644,12 +695,13 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
 
 
 	// Create and set network handler in driver
 	// Create and set network handler in driver
 	network := &bridgeNetwork{
 	network := &bridgeNetwork{
-		id:         config.ID,
-		endpoints:  make(map[string]*bridgeEndpoint),
-		config:     config,
-		portMapper: portmapper.New(d.config.UserlandProxyPath),
-		bridge:     bridgeIface,
-		driver:     d,
+		id:           config.ID,
+		endpoints:    make(map[string]*bridgeEndpoint),
+		config:       config,
+		portMapper:   portmapper.New(d.config.UserlandProxyPath),
+		portMapperV6: portmapper.New(d.config.UserlandProxyPath),
+		bridge:       bridgeIface,
+		driver:       d,
 	}
 	}
 
 
 	d.Lock()
 	d.Lock()
@@ -724,11 +776,16 @@ func (d *driver) createNetwork(config *networkConfiguration) (err error) {
 		{!d.config.EnableUserlandProxy, setupLoopbackAddressesRouting},
 		{!d.config.EnableUserlandProxy, setupLoopbackAddressesRouting},
 
 
 		// Setup IPTables.
 		// Setup IPTables.
-		{d.config.EnableIPTables, network.setupIPTables},
+		{d.config.EnableIPTables, network.setupIP4Tables},
+
+		// Setup IP6Tables.
+		{d.config.EnableIP6Tables, network.setupIP6Tables},
 
 
 		//We want to track firewalld configuration so that
 		//We want to track firewalld configuration so that
 		//if it is started/reloaded, the rules can be applied correctly
 		//if it is started/reloaded, the rules can be applied correctly
 		{d.config.EnableIPTables, network.setupFirewalld},
 		{d.config.EnableIPTables, network.setupFirewalld},
+		// same for IPv6
+		{d.config.EnableIP6Tables, network.setupFirewalld6},
 
 
 		// Setup DefaultGatewayIPv4
 		// Setup DefaultGatewayIPv4
 		{config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
 		{config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},

+ 36 - 4
vendor/github.com/docker/libnetwork/drivers/bridge/port_mapping.go

@@ -12,7 +12,8 @@ import (
 )
 )
 
 
 var (
 var (
-	defaultBindingIP = net.IPv4(0, 0, 0, 0)
+	defaultBindingIP   = net.IPv4(0, 0, 0, 0)
+	defaultBindingIPV6 = net.ParseIP("::")
 )
 )
 
 
 func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
 func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
@@ -25,7 +26,25 @@ func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, u
 		defHostIP = reqDefBindIP
 		defHostIP = reqDefBindIP
 	}
 	}
 
 
-	return n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
+	// IPv4 port binding including user land proxy
+	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, defHostIP, ulPxyEnabled)
+	if err != nil {
+		return nil, err
+	}
+
+	// IPv6 port binding excluding user land proxy
+	if n.driver.config.EnableIP6Tables && ep.addrv6 != nil {
+		// TODO IPv6 custom default binding IP
+		pbv6, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addrv6.IP, defaultBindingIPV6, false)
+		if err != nil {
+			// ensure we clear the previous allocated IPv4 ports
+			n.releasePortsInternal(pb)
+			return nil, err
+		}
+
+		pb = append(pb, pbv6...)
+	}
+	return pb, nil
 }
 }
 
 
 func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
 func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIP, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
@@ -69,9 +88,15 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
 		return err
 		return err
 	}
 	}
 
 
+	portmapper := n.portMapper
+
+	if containerIP.To4() == nil {
+		portmapper = n.portMapperV6
+	}
+
 	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
 	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
 	for i := 0; i < maxAllocatePortAttempts; i++ {
 	for i := 0; i < maxAllocatePortAttempts; i++ {
-		if host, err = n.portMapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
+		if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
 			break
 			break
 		}
 		}
 		// There is no point in immediately retrying to map an explicitly chosen port.
 		// There is no point in immediately retrying to map an explicitly chosen port.
@@ -128,5 +153,12 @@ func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	return n.portMapper.Unmap(host)
+
+	portmapper := n.portMapper
+
+	if bnd.HostIP.To4() == nil {
+		portmapper = n.portMapperV6
+	}
+
+	return portmapper.Unmap(host)
 }
 }

+ 16 - 1
vendor/github.com/docker/libnetwork/drivers/bridge/setup_firewalld.go

@@ -13,8 +13,23 @@ func (n *bridgeNetwork) setupFirewalld(config *networkConfiguration, i *bridgeIn
 		return IPTableCfgError(config.BridgeName)
 		return IPTableCfgError(config.BridgeName)
 	}
 	}
 
 
-	iptables.OnReloaded(func() { n.setupIPTables(config, i) })
+	iptables.OnReloaded(func() { n.setupIP4Tables(config, i) })
 	iptables.OnReloaded(n.portMapper.ReMapAll)
 	iptables.OnReloaded(n.portMapper.ReMapAll)
+	return nil
+}
+
+func (n *bridgeNetwork) setupFirewalld6(config *networkConfiguration, i *bridgeInterface) error {
+	d := n.driver
+	d.Lock()
+	driverConfig := d.config
+	d.Unlock()
+
+	// Sanity check.
+	if !driverConfig.EnableIP6Tables {
+		return IPTableCfgError(config.BridgeName)
+	}
 
 
+	iptables.OnReloaded(func() { n.setupIP6Tables(config, i) })
+	iptables.OnReloaded(n.portMapperV6.ReMapAll)
 	return nil
 	return nil
 }
 }

+ 24 - 9
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_forwarding.go

@@ -21,7 +21,7 @@ func configureIPForwarding(enable bool) error {
 	return ioutil.WriteFile(ipv4ForwardConf, []byte{val, '\n'}, ipv4ForwardConfPerm)
 	return ioutil.WriteFile(ipv4ForwardConf, []byte{val, '\n'}, ipv4ForwardConfPerm)
 }
 }
 
 
-func setupIPForwarding(enableIPTables bool) error {
+func setupIPForwarding(enableIPTables bool, enableIP6Tables bool) error {
 	// Get current IPv4 forward setup
 	// Get current IPv4 forward setup
 	ipv4ForwardData, err := ioutil.ReadFile(ipv4ForwardConf)
 	ipv4ForwardData, err := ioutil.ReadFile(ipv4ForwardConf)
 	if err != nil {
 	if err != nil {
@@ -36,21 +36,36 @@ func setupIPForwarding(enableIPTables bool) error {
 		}
 		}
 		// When enabling ip_forward set the default policy on forward chain to
 		// When enabling ip_forward set the default policy on forward chain to
 		// drop only if the daemon option iptables is not set to false.
 		// drop only if the daemon option iptables is not set to false.
-		if !enableIPTables {
-			return nil
-		}
-		if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
-			if err := configureIPForwarding(false); err != nil {
-				logrus.Errorf("Disabling IP forwarding failed, %v", err)
+		if enableIPTables {
+			iptable := iptables.GetIptable(iptables.IPv4)
+			if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
+				if err := configureIPForwarding(false); err != nil {
+					logrus.Errorf("Disabling IP forwarding failed, %v", err)
+				}
+				return err
 			}
 			}
-			return err
+			iptables.OnReloaded(func() {
+				logrus.Debug("Setting the default DROP policy on firewall reload")
+				if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
+					logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
+				}
+			})
+		}
+	}
+
+	// add only iptables rules - forwarding is handled by setupIPv6Forwarding in setup_ipv6
+	if enableIP6Tables {
+		iptable := iptables.GetIptable(iptables.IPv6)
+		if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
+			logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
 		}
 		}
 		iptables.OnReloaded(func() {
 		iptables.OnReloaded(func() {
 			logrus.Debug("Setting the default DROP policy on firewall reload")
 			logrus.Debug("Setting the default DROP policy on firewall reload")
-			if err := iptables.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
+			if err := iptable.SetDefaultPolicy(iptables.Filter, "FORWARD", iptables.Drop); err != nil {
 				logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
 				logrus.Warnf("Setting the default DROP policy on firewall reload failed, %v", err)
 			}
 			}
 		})
 		})
 	}
 	}
+
 	return nil
 	return nil
 }
 }

+ 115 - 66
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go

@@ -26,7 +26,7 @@ const (
 	IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
 	IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
 )
 )
 
 
-func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
+func setupIPChains(config *configuration, version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
 	// Sanity check.
 	// Sanity check.
 	if config.EnableIPTables == false {
 	if config.EnableIPTables == false {
 		return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
 		return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
@@ -34,129 +34,157 @@ func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainI
 
 
 	hairpinMode := !config.EnableUserlandProxy
 	hairpinMode := !config.EnableUserlandProxy
 
 
-	natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode)
+	iptable := iptables.GetIptable(version)
+
+	natChain, err := iptable.NewChain(DockerChain, iptables.Nat, hairpinMode)
 	if err != nil {
 	if err != nil {
 		return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
 		return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
 	}
 	}
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
-			if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
+			if err := iptable.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
 				logrus.Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
 				logrus.Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
 			}
 			}
 		}
 		}
 	}()
 	}()
 
 
-	filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, false)
+	filterChain, err := iptable.NewChain(DockerChain, iptables.Filter, false)
 	if err != nil {
 	if err != nil {
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
 	}
 	}
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
-			if err := iptables.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
+			if err := iptable.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
 			}
 			}
 		}
 		}
 	}()
 	}()
 
 
-	isolationChain1, err := iptables.NewChain(IsolationChain1, iptables.Filter, false)
+	isolationChain1, err := iptable.NewChain(IsolationChain1, iptables.Filter, false)
 	if err != nil {
 	if err != nil {
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
 	}
 	}
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
-			if err := iptables.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
+			if err := iptable.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
 			}
 			}
 		}
 		}
 	}()
 	}()
 
 
-	isolationChain2, err := iptables.NewChain(IsolationChain2, iptables.Filter, false)
+	isolationChain2, err := iptable.NewChain(IsolationChain2, iptables.Filter, false)
 	if err != nil {
 	if err != nil {
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
 		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
 	}
 	}
 	defer func() {
 	defer func() {
 		if err != nil {
 		if err != nil {
-			if err := iptables.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
+			if err := iptable.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
 				logrus.Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
 			}
 			}
 		}
 		}
 	}()
 	}()
 
 
-	if err := iptables.AddReturnRule(IsolationChain1); err != nil {
+	if err := iptable.AddReturnRule(IsolationChain1); err != nil {
 		return nil, nil, nil, nil, err
 		return nil, nil, nil, nil, err
 	}
 	}
 
 
-	if err := iptables.AddReturnRule(IsolationChain2); err != nil {
+	if err := iptable.AddReturnRule(IsolationChain2); err != nil {
 		return nil, nil, nil, nil, err
 		return nil, nil, nil, nil, err
 	}
 	}
 
 
 	return natChain, filterChain, isolationChain1, isolationChain2, nil
 	return natChain, filterChain, isolationChain1, isolationChain2, nil
 }
 }
 
 
-func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error {
-	var err error
-
+func (n *bridgeNetwork) setupIP4Tables(config *networkConfiguration, i *bridgeInterface) error {
 	d := n.driver
 	d := n.driver
 	d.Lock()
 	d.Lock()
 	driverConfig := d.config
 	driverConfig := d.config
 	d.Unlock()
 	d.Unlock()
 
 
 	// Sanity check.
 	// Sanity check.
-	if driverConfig.EnableIPTables == false {
+	if !driverConfig.EnableIPTables {
 		return errors.New("Cannot program chains, EnableIPTable is disabled")
 		return errors.New("Cannot program chains, EnableIPTable is disabled")
 	}
 	}
 
 
-	// Pickup this configuration option from driver
-	hairpinMode := !driverConfig.EnableUserlandProxy
-
 	maskedAddrv4 := &net.IPNet{
 	maskedAddrv4 := &net.IPNet{
 		IP:   i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
 		IP:   i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
 		Mask: i.bridgeIPv4.Mask,
 		Mask: i.bridgeIPv4.Mask,
 	}
 	}
+	return n.setupIPTables(iptables.IPv4, maskedAddrv4, config, i)
+}
+
+func (n *bridgeNetwork) setupIP6Tables(config *networkConfiguration, i *bridgeInterface) error {
+	d := n.driver
+	d.Lock()
+	driverConfig := d.config
+	d.Unlock()
+
+	// Sanity check.
+	if !driverConfig.EnableIP6Tables {
+		return errors.New("Cannot program chains, EnableIP6Tables is disabled")
+	}
+
+	maskedAddrv6 := &net.IPNet{
+		IP:   i.bridgeIPv6.IP.Mask(i.bridgeIPv6.Mask),
+		Mask: i.bridgeIPv6.Mask,
+	}
+
+	return n.setupIPTables(iptables.IPv6, maskedAddrv6, config, i)
+}
+
+func (n *bridgeNetwork) setupIPTables(ipVersion iptables.IPVersion, maskedAddr *net.IPNet, config *networkConfiguration, i *bridgeInterface) error {
+	var err error
+
+	d := n.driver
+	d.Lock()
+	driverConfig := d.config
+	d.Unlock()
+
+	// Pickup this configuration option from driver
+	hairpinMode := !driverConfig.EnableUserlandProxy
+
+	iptable := iptables.GetIptable(ipVersion)
+
 	if config.Internal {
 	if config.Internal {
-		if err = setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, true); err != nil {
+		if err = setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, true); err != nil {
 			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
 			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
 		}
 		}
 		n.registerIptCleanFunc(func() error {
 		n.registerIptCleanFunc(func() error {
-			return setupInternalNetworkRules(config.BridgeName, maskedAddrv4, config.EnableICC, false)
+			return setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, false)
 		})
 		})
 	} else {
 	} else {
-		if err = setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
+		if err = setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
 			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
 			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
 		}
 		}
 		n.registerIptCleanFunc(func() error {
 		n.registerIptCleanFunc(func() error {
-			return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
+			return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
 		})
 		})
-		natChain, filterChain, _, _, err := n.getDriverChains()
+		natChain, filterChain, _, _, err := n.getDriverChains(ipVersion)
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
 			return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
 		}
 		}
 
 
-		err = iptables.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
+		err = iptable.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
 			return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
 		}
 		}
 
 
-		err = iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
+		err = iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
 			return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
 		}
 		}
 
 
 		n.registerIptCleanFunc(func() error {
 		n.registerIptCleanFunc(func() error {
-			return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
+			return iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
 		})
 		})
 
 
 		n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
 		n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
 	}
 	}
 
 
 	d.Lock()
 	d.Lock()
-	err = iptables.EnsureJumpRule("FORWARD", IsolationChain1)
+	err = iptable.EnsureJumpRule("FORWARD", IsolationChain1)
 	d.Unlock()
 	d.Unlock()
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return err
 }
 }
 
 
 type iptRule struct {
 type iptRule struct {
@@ -166,7 +194,7 @@ type iptRule struct {
 	args    []string
 	args    []string
 }
 }
 
 
-func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr net.Addr, icc, ipmasq, hairpin, enable bool) error {
+func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr *net.IPNet, icc, ipmasq, hairpin, enable bool) error {
 
 
 	var (
 	var (
 		address   = addr.String()
 		address   = addr.String()
@@ -189,41 +217,50 @@ func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr net.Addr, icc
 	natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
 	natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
 	hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
 	hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
 
 
+	ipVersion := iptables.IPv4
+
+	if addr.IP.To4() == nil {
+		ipVersion = iptables.IPv6
+	}
+
 	// Set NAT.
 	// Set NAT.
 	if ipmasq {
 	if ipmasq {
-		if err := programChainRule(natRule, "NAT", enable); err != nil {
+		if err := programChainRule(ipVersion, natRule, "NAT", enable); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 
 
 	if ipmasq && !hairpin {
 	if ipmasq && !hairpin {
-		if err := programChainRule(skipDNAT, "SKIP DNAT", enable); err != nil {
+		if err := programChainRule(ipVersion, skipDNAT, "SKIP DNAT", enable); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 
 
 	// In hairpin mode, masquerade traffic from localhost
 	// In hairpin mode, masquerade traffic from localhost
 	if hairpin {
 	if hairpin {
-		if err := programChainRule(hpNatRule, "MASQ LOCAL HOST", enable); err != nil {
+		if err := programChainRule(ipVersion, hpNatRule, "MASQ LOCAL HOST", enable); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 
 
 	// Set Inter Container Communication.
 	// Set Inter Container Communication.
-	if err := setIcc(bridgeIface, icc, enable); err != nil {
+	if err := setIcc(ipVersion, bridgeIface, icc, enable); err != nil {
 		return err
 		return err
 	}
 	}
 
 
 	// Set Accept on all non-intercontainer outgoing packets.
 	// Set Accept on all non-intercontainer outgoing packets.
-	return programChainRule(outRule, "ACCEPT NON_ICC OUTGOING", enable)
+	return programChainRule(ipVersion, outRule, "ACCEPT NON_ICC OUTGOING", enable)
 }
 }
 
 
-func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
+func programChainRule(version iptables.IPVersion, rule iptRule, ruleDescr string, insert bool) error {
+
+	iptable := iptables.GetIptable(version)
+
 	var (
 	var (
 		prefix    []string
 		prefix    []string
 		operation string
 		operation string
 		condition bool
 		condition bool
-		doesExist = iptables.Exists(rule.table, rule.chain, rule.args...)
+		doesExist = iptable.Exists(rule.table, rule.chain, rule.args...)
 	)
 	)
 
 
 	if insert {
 	if insert {
@@ -240,7 +277,7 @@ func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
 	}
 	}
 
 
 	if condition {
 	if condition {
-		if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
+		if err := iptable.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
 			return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
 			return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
 		}
 		}
 	}
 	}
@@ -248,7 +285,8 @@ func programChainRule(rule iptRule, ruleDescr string, insert bool) error {
 	return nil
 	return nil
 }
 }
 
 
-func setIcc(bridgeIface string, iccEnable, insert bool) error {
+func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, insert bool) error {
+	iptable := iptables.GetIptable(version)
 	var (
 	var (
 		table      = iptables.Filter
 		table      = iptables.Filter
 		chain      = "FORWARD"
 		chain      = "FORWARD"
@@ -259,18 +297,18 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
 
 
 	if insert {
 	if insert {
 		if !iccEnable {
 		if !iccEnable {
-			iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
+			iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
 
 
-			if !iptables.Exists(table, chain, dropArgs...) {
-				if err := iptables.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
+			if !iptable.Exists(table, chain, dropArgs...) {
+				if err := iptable.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
 					return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
 					return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
 				}
 				}
 			}
 			}
 		} else {
 		} else {
-			iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
+			iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
 
 
-			if !iptables.Exists(table, chain, acceptArgs...) {
-				if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
+			if !iptable.Exists(table, chain, acceptArgs...) {
+				if err := iptable.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
 					return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
 					return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
 				}
 				}
 			}
 			}
@@ -278,12 +316,12 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
 	} else {
 	} else {
 		// Remove any ICC rule.
 		// Remove any ICC rule.
 		if !iccEnable {
 		if !iccEnable {
-			if iptables.Exists(table, chain, dropArgs...) {
-				iptables.Raw(append([]string{"-D", chain}, dropArgs...)...)
+			if iptable.Exists(table, chain, dropArgs...) {
+				iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
 			}
 			}
 		} else {
 		} else {
-			if iptables.Exists(table, chain, acceptArgs...) {
-				iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...)
+			if iptable.Exists(table, chain, acceptArgs...) {
+				iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
 			}
 			}
 		}
 		}
 	}
 	}
@@ -292,7 +330,8 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error {
 }
 }
 
 
 // Control Inter Network Communication. Install[Remove] only if it is [not] present.
 // Control Inter Network Communication. Install[Remove] only if it is [not] present.
-func setINC(iface string, enable bool) error {
+func setINC(version iptables.IPVersion, iface string, enable bool) error {
+	iptable := iptables.GetIptable(version)
 	var (
 	var (
 		action    = iptables.Insert
 		action    = iptables.Insert
 		actionMsg = "add"
 		actionMsg = "add"
@@ -309,12 +348,12 @@ func setINC(iface string, enable bool) error {
 	}
 	}
 
 
 	for i, chain := range chains {
 	for i, chain := range chains {
-		if err := iptables.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
+		if err := iptable.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
 			msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
 			msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
 			if enable {
 			if enable {
 				if i == 1 {
 				if i == 1 {
 					// Rollback the rule installed on first chain
 					// Rollback the rule installed on first chain
-					if err2 := iptables.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
+					if err2 := iptable.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
 						logrus.Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
 						logrus.Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
 					}
 					}
 				}
 				}
@@ -330,37 +369,47 @@ func setINC(iface string, enable bool) error {
 // Obsolete chain from previous docker versions
 // Obsolete chain from previous docker versions
 const oldIsolationChain = "DOCKER-ISOLATION"
 const oldIsolationChain = "DOCKER-ISOLATION"
 
 
-func removeIPChains() {
+func removeIPChains(version iptables.IPVersion) {
+	ipt := iptables.IPTable{Version: version}
+
 	// Remove obsolete rules from default chains
 	// Remove obsolete rules from default chains
-	iptables.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
+	ipt.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
 
 
 	// Remove chains
 	// Remove chains
 	for _, chainInfo := range []iptables.ChainInfo{
 	for _, chainInfo := range []iptables.ChainInfo{
-		{Name: DockerChain, Table: iptables.Nat},
-		{Name: DockerChain, Table: iptables.Filter},
-		{Name: IsolationChain1, Table: iptables.Filter},
-		{Name: IsolationChain2, Table: iptables.Filter},
-		{Name: oldIsolationChain, Table: iptables.Filter},
+		{Name: DockerChain, Table: iptables.Nat, IPTable: ipt},
+		{Name: DockerChain, Table: iptables.Filter, IPTable: ipt},
+		{Name: IsolationChain1, Table: iptables.Filter, IPTable: ipt},
+		{Name: IsolationChain2, Table: iptables.Filter, IPTable: ipt},
+		{Name: oldIsolationChain, Table: iptables.Filter, IPTable: ipt},
 	} {
 	} {
+
 		if err := chainInfo.Remove(); err != nil {
 		if err := chainInfo.Remove(); err != nil {
 			logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
 			logrus.Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
 		}
 		}
 	}
 	}
 }
 }
 
 
-func setupInternalNetworkRules(bridgeIface string, addr net.Addr, icc, insert bool) error {
+func setupInternalNetworkRules(bridgeIface string, addr *net.IPNet, icc, insert bool) error {
 	var (
 	var (
 		inDropRule  = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
 		inDropRule  = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"}}
 		outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
 		outDropRule = iptRule{table: iptables.Filter, chain: IsolationChain1, args: []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"}}
 	)
 	)
-	if err := programChainRule(inDropRule, "DROP INCOMING", insert); err != nil {
+
+	version := iptables.IPv4
+
+	if addr.IP.To4() == nil {
+		version = iptables.IPv6
+	}
+
+	if err := programChainRule(version, inDropRule, "DROP INCOMING", insert); err != nil {
 		return err
 		return err
 	}
 	}
-	if err := programChainRule(outDropRule, "DROP OUTGOING", insert); err != nil {
+	if err := programChainRule(version, outDropRule, "DROP OUTGOING", insert); err != nil {
 		return err
 		return err
 	}
 	}
 	// Set Inter Container Communication.
 	// Set Inter Container Communication.
-	return setIcc(bridgeIface, icc, insert)
+	return setIcc(version, bridgeIface, icc, insert)
 }
 }
 
 
 func clearEndpointConnections(nlh *netlink.Handle, ep *bridgeEndpoint) {
 func clearEndpointConnections(nlh *netlink.Handle, ep *bridgeEndpoint) {

+ 10 - 4
vendor/github.com/docker/libnetwork/drivers/overlay/encryption.go

@@ -210,7 +210,10 @@ func programMangle(vni uint32, add bool) (err error) {
 		action = "install"
 		action = "install"
 	)
 	)
 
 
-	if add == iptables.Exists(iptables.Mangle, chain, rule...) {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+
+	if add == iptable.Exists(iptables.Mangle, chain, rule...) {
 		return
 		return
 	}
 	}
 
 
@@ -219,7 +222,7 @@ func programMangle(vni uint32, add bool) (err error) {
 		action = "remove"
 		action = "remove"
 	}
 	}
 
 
-	if err = iptables.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil {
+	if err = iptable.RawCombinedOutput(append([]string{"-t", string(iptables.Mangle), a, chain}, rule...)...); err != nil {
 		logrus.Warnf("could not %s mangle rule: %v", action, err)
 		logrus.Warnf("could not %s mangle rule: %v", action, err)
 	}
 	}
 
 
@@ -239,16 +242,19 @@ func programInput(vni uint32, add bool) (err error) {
 		msg        = "add"
 		msg        = "add"
 	)
 	)
 
 
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+
 	if !add {
 	if !add {
 		action = iptables.Delete
 		action = iptables.Delete
 		msg = "remove"
 		msg = "remove"
 	}
 	}
 
 
-	if err := iptables.ProgramRule(iptables.Filter, chain, action, accept); err != nil {
+	if err := iptable.ProgramRule(iptables.Filter, chain, action, accept); err != nil {
 		logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
 		logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
 	}
 	}
 
 
-	if err := iptables.ProgramRule(iptables.Filter, chain, action, block); err != nil {
+	if err := iptable.ProgramRule(iptables.Filter, chain, action, block); err != nil {
 		logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
 		logrus.Errorf("could not %s input rule: %v. Please do it manually.", msg, err)
 	}
 	}
 
 

+ 23 - 15
vendor/github.com/docker/libnetwork/drivers/overlay/filter.go

@@ -20,7 +20,9 @@ func filterWait() func() {
 }
 }
 
 
 func chainExists(cname string) bool {
 func chainExists(cname string) bool {
-	if _, err := iptables.Raw("-L", cname); err != nil {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+	if _, err := iptable.Raw("-L", cname); err != nil {
 		return false
 		return false
 	}
 	}
 
 
@@ -28,22 +30,26 @@ func chainExists(cname string) bool {
 }
 }
 
 
 func setupGlobalChain() {
 func setupGlobalChain() {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
 	// Because of an ungraceful shutdown, chain could already be present
 	// Because of an ungraceful shutdown, chain could already be present
 	if !chainExists(globalChain) {
 	if !chainExists(globalChain) {
-		if err := iptables.RawCombinedOutput("-N", globalChain); err != nil {
+		if err := iptable.RawCombinedOutput("-N", globalChain); err != nil {
 			logrus.Errorf("could not create global overlay chain: %v", err)
 			logrus.Errorf("could not create global overlay chain: %v", err)
 			return
 			return
 		}
 		}
 	}
 	}
 
 
-	if !iptables.Exists(iptables.Filter, globalChain, "-j", "RETURN") {
-		if err := iptables.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
+	if !iptable.Exists(iptables.Filter, globalChain, "-j", "RETURN") {
+		if err := iptable.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil {
 			logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
 			logrus.Errorf("could not install default return chain in the overlay global chain: %v", err)
 		}
 		}
 	}
 	}
 }
 }
 
 
 func setNetworkChain(cname string, remove bool) error {
 func setNetworkChain(cname string, remove bool) error {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
 	// Initialize the onetime global overlay chain
 	// Initialize the onetime global overlay chain
 	filterOnce.Do(setupGlobalChain)
 	filterOnce.Do(setupGlobalChain)
 
 
@@ -52,21 +58,21 @@ func setNetworkChain(cname string, remove bool) error {
 	opt := "-N"
 	opt := "-N"
 	// In case of remove, make sure to flush the rules in the chain
 	// In case of remove, make sure to flush the rules in the chain
 	if remove && exists {
 	if remove && exists {
-		if err := iptables.RawCombinedOutput("-F", cname); err != nil {
+		if err := iptable.RawCombinedOutput("-F", cname); err != nil {
 			return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
 			return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err)
 		}
 		}
 		opt = "-X"
 		opt = "-X"
 	}
 	}
 
 
 	if (!remove && !exists) || (remove && exists) {
 	if (!remove && !exists) || (remove && exists) {
-		if err := iptables.RawCombinedOutput(opt, cname); err != nil {
+		if err := iptable.RawCombinedOutput(opt, cname); err != nil {
 			return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
 			return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err)
 		}
 		}
 	}
 	}
 
 
 	if !remove {
 	if !remove {
-		if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") {
-			if err := iptables.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil {
+		if !iptable.Exists(iptables.Filter, cname, "-j", "DROP") {
+			if err := iptable.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil {
 				return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
 				return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err)
 			}
 			}
 		}
 		}
@@ -92,37 +98,39 @@ func setFilters(cname, brName string, remove bool) error {
 	if remove {
 	if remove {
 		opt = "-D"
 		opt = "-D"
 	}
 	}
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
 
 
 	// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
 	// Every time we set filters for a new subnet make sure to move the global overlay hook to the top of the both the OUTPUT and forward chains
 	if !remove {
 	if !remove {
 		for _, chain := range []string{"OUTPUT", "FORWARD"} {
 		for _, chain := range []string{"OUTPUT", "FORWARD"} {
-			exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain)
+			exists := iptable.Exists(iptables.Filter, chain, "-j", globalChain)
 			if exists {
 			if exists {
-				if err := iptables.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil {
+				if err := iptable.RawCombinedOutput("-D", chain, "-j", globalChain); err != nil {
 					return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
 					return fmt.Errorf("failed to delete overlay hook in chain %s while moving the hook: %v", chain, err)
 				}
 				}
 			}
 			}
 
 
-			if err := iptables.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil {
+			if err := iptable.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil {
 				return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
 				return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err)
 			}
 			}
 		}
 		}
 	}
 	}
 
 
 	// Insert/Delete the rule to jump to per-bridge chain
 	// Insert/Delete the rule to jump to per-bridge chain
-	exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
+	exists := iptable.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname)
 	if (!remove && !exists) || (remove && exists) {
 	if (!remove && !exists) || (remove && exists) {
-		if err := iptables.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil {
+		if err := iptable.RawCombinedOutput(opt, globalChain, "-o", brName, "-j", cname); err != nil {
 			return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
 			return fmt.Errorf("failed to add per-bridge filter rule for bridge %s, network chain %s: %v", brName, cname, err)
 		}
 		}
 	}
 	}
 
 
-	exists = iptables.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
+	exists = iptable.Exists(iptables.Filter, cname, "-i", brName, "-j", "ACCEPT")
 	if (!remove && exists) || (remove && !exists) {
 	if (!remove && exists) || (remove && !exists) {
 		return nil
 		return nil
 	}
 	}
 
 
-	if err := iptables.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
+	if err := iptable.RawCombinedOutput(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil {
 		return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
 		return fmt.Errorf("failed to add overlay filter rile for network chain %s, bridge %s: %v", cname, brName, err)
 	}
 	}
 
 

+ 5 - 3
vendor/github.com/docker/libnetwork/firewall_linux.go

@@ -26,18 +26,20 @@ func arrangeUserFilterRule() {
 	if ctrl == nil || !ctrl.iptablesEnabled() {
 	if ctrl == nil || !ctrl.iptablesEnabled() {
 		return
 		return
 	}
 	}
-	_, err := iptables.NewChain(userChain, iptables.Filter, false)
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+	_, err := iptable.NewChain(userChain, iptables.Filter, false)
 	if err != nil {
 	if err != nil {
 		logrus.Warnf("Failed to create %s chain: %v", userChain, err)
 		logrus.Warnf("Failed to create %s chain: %v", userChain, err)
 		return
 		return
 	}
 	}
 
 
-	if err = iptables.AddReturnRule(userChain); err != nil {
+	if err = iptable.AddReturnRule(userChain); err != nil {
 		logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err)
 		logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err)
 		return
 		return
 	}
 	}
 
 
-	err = iptables.EnsureJumpRule("FORWARD", userChain)
+	err = iptable.EnsureJumpRule("FORWARD", userChain)
 	if err != nil {
 	if err != nil {
 		logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err)
 		logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err)
 	}
 	}

+ 120 - 64
vendor/github.com/docker/libnetwork/iptables/iptables.go

@@ -23,6 +23,9 @@ type Policy string
 // Table refers to Nat, Filter or Mangle.
 // Table refers to Nat, Filter or Mangle.
 type Table string
 type Table string
 
 
+// IPVersion refers to IP version, v4 or v6
+type IPVersion string
+
 const (
 const (
 	// Append appends the rule at the end of the chain.
 	// Append appends the rule at the end of the chain.
 	Append Action = "-A"
 	Append Action = "-A"
@@ -40,10 +43,15 @@ const (
 	Drop Policy = "DROP"
 	Drop Policy = "DROP"
 	// Accept is the default iptables ACCEPT policy
 	// Accept is the default iptables ACCEPT policy
 	Accept Policy = "ACCEPT"
 	Accept Policy = "ACCEPT"
+	// IPv4 is version 4
+	IPv4 IPVersion = "IPV4"
+	// IPv6 is version 6
+	IPv6 IPVersion = "IPV6"
 )
 )
 
 
 var (
 var (
 	iptablesPath  string
 	iptablesPath  string
+	ip6tablesPath string
 	supportsXlock = false
 	supportsXlock = false
 	supportsCOpt  = false
 	supportsCOpt  = false
 	xLockWaitMsg  = "Another app is currently holding the xtables lock"
 	xLockWaitMsg  = "Another app is currently holding the xtables lock"
@@ -54,11 +62,17 @@ var (
 	initOnce            sync.Once
 	initOnce            sync.Once
 )
 )
 
 
+// IPTable defines struct with IPVersion
+type IPTable struct {
+	Version IPVersion
+}
+
 // ChainInfo defines the iptables chain.
 // ChainInfo defines the iptables chain.
 type ChainInfo struct {
 type ChainInfo struct {
 	Name        string
 	Name        string
 	Table       Table
 	Table       Table
 	HairpinMode bool
 	HairpinMode bool
+	IPTable     IPTable
 }
 }
 
 
 // ChainError is returned to represent errors during ip table operation.
 // ChainError is returned to represent errors during ip table operation.
@@ -80,6 +94,11 @@ func probe() {
 	if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
 	if out, err := exec.Command(path, "--wait", "-t", "nat", "-L", "-n").CombinedOutput(); err != nil {
 		logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
 		logrus.Warnf("Running iptables --wait -t nat -L -n failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
 	}
 	}
+	_, err = exec.LookPath("ip6tables")
+	if err != nil {
+		logrus.Warnf("Failed to find ip6tables: %v", err)
+		return
+	}
 }
 }
 
 
 func initFirewalld() {
 func initFirewalld() {
@@ -94,6 +113,11 @@ func detectIptables() {
 		return
 		return
 	}
 	}
 	iptablesPath = path
 	iptablesPath = path
+	path, err = exec.LookPath("ip6tables")
+	if err != nil {
+		return
+	}
+	ip6tablesPath = path
 	supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
 	supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
 	mj, mn, mc, err := GetVersion()
 	mj, mn, mc, err := GetVersion()
 	if err != nil {
 	if err != nil {
@@ -118,20 +142,26 @@ func initCheck() error {
 	return nil
 	return nil
 }
 }
 
 
+// GetIptable returns an instance of IPTable with specified version
+func GetIptable(version IPVersion) *IPTable {
+	return &IPTable{Version: version}
+}
+
 // NewChain adds a new chain to ip table.
 // NewChain adds a new chain to ip table.
-func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
+func (iptable IPTable) NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
 	c := &ChainInfo{
 	c := &ChainInfo{
 		Name:        name,
 		Name:        name,
 		Table:       table,
 		Table:       table,
 		HairpinMode: hairpinMode,
 		HairpinMode: hairpinMode,
+		IPTable:     iptable,
 	}
 	}
 	if string(c.Table) == "" {
 	if string(c.Table) == "" {
 		c.Table = Filter
 		c.Table = Filter
 	}
 	}
 
 
 	// Add chain if it doesn't exist
 	// Add chain if it doesn't exist
-	if _, err := Raw("-t", string(c.Table), "-n", "-L", c.Name); err != nil {
-		if output, err := Raw("-t", string(c.Table), "-N", c.Name); err != nil {
+	if _, err := iptable.Raw("-t", string(c.Table), "-n", "-L", c.Name); err != nil {
+		if output, err := iptable.Raw("-t", string(c.Table), "-N", c.Name); err != nil {
 			return nil, err
 			return nil, err
 		} else if len(output) != 0 {
 		} else if len(output) != 0 {
 			return nil, fmt.Errorf("Could not create %s/%s chain: %s", c.Table, c.Name, output)
 			return nil, fmt.Errorf("Could not create %s/%s chain: %s", c.Table, c.Name, output)
@@ -140,8 +170,16 @@ func NewChain(name string, table Table, hairpinMode bool) (*ChainInfo, error) {
 	return c, nil
 	return c, nil
 }
 }
 
 
+// LoopbackByVersion returns loopback address by version
+func (iptable IPTable) LoopbackByVersion() string {
+	if iptable.Version == IPv6 {
+		return "::1/128"
+	}
+	return "127.0.0.0/8"
+}
+
 // ProgramChain is used to add rules to a chain
 // ProgramChain is used to add rules to a chain
-func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
+func (iptable IPTable) ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) error {
 	if c.Name == "" {
 	if c.Name == "" {
 		return errors.New("Could not program chain, missing chain name")
 		return errors.New("Could not program chain, missing chain name")
 	}
 	}
@@ -165,11 +203,11 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
 			"-m", "addrtype",
 			"-m", "addrtype",
 			"--dst-type", "LOCAL",
 			"--dst-type", "LOCAL",
 			"-j", c.Name}
 			"-j", c.Name}
-		if !Exists(Nat, "PREROUTING", preroute...) && enable {
+		if !iptable.Exists(Nat, "PREROUTING", preroute...) && enable {
 			if err := c.Prerouting(Append, preroute...); err != nil {
 			if err := c.Prerouting(Append, preroute...); err != nil {
 				return fmt.Errorf("Failed to inject %s in PREROUTING chain: %s", c.Name, err)
 				return fmt.Errorf("Failed to inject %s in PREROUTING chain: %s", c.Name, err)
 			}
 			}
-		} else if Exists(Nat, "PREROUTING", preroute...) && !enable {
+		} else if iptable.Exists(Nat, "PREROUTING", preroute...) && !enable {
 			if err := c.Prerouting(Delete, preroute...); err != nil {
 			if err := c.Prerouting(Delete, preroute...); err != nil {
 				return fmt.Errorf("Failed to remove %s in PREROUTING chain: %s", c.Name, err)
 				return fmt.Errorf("Failed to remove %s in PREROUTING chain: %s", c.Name, err)
 			}
 			}
@@ -179,13 +217,13 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
 			"--dst-type", "LOCAL",
 			"--dst-type", "LOCAL",
 			"-j", c.Name}
 			"-j", c.Name}
 		if !hairpinMode {
 		if !hairpinMode {
-			output = append(output, "!", "--dst", "127.0.0.0/8")
+			output = append(output, "!", "--dst", iptable.LoopbackByVersion())
 		}
 		}
-		if !Exists(Nat, "OUTPUT", output...) && enable {
+		if !iptable.Exists(Nat, "OUTPUT", output...) && enable {
 			if err := c.Output(Append, output...); err != nil {
 			if err := c.Output(Append, output...); err != nil {
 				return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
 				return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
 			}
 			}
-		} else if Exists(Nat, "OUTPUT", output...) && !enable {
+		} else if iptable.Exists(Nat, "OUTPUT", output...) && !enable {
 			if err := c.Output(Delete, output...); err != nil {
 			if err := c.Output(Delete, output...); err != nil {
 				return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
 				return fmt.Errorf("Failed to inject %s in OUTPUT chain: %s", c.Name, err)
 			}
 			}
@@ -198,16 +236,16 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
 		link := []string{
 		link := []string{
 			"-o", bridgeName,
 			"-o", bridgeName,
 			"-j", c.Name}
 			"-j", c.Name}
-		if !Exists(Filter, "FORWARD", link...) && enable {
+		if !iptable.Exists(Filter, "FORWARD", link...) && enable {
 			insert := append([]string{string(Insert), "FORWARD"}, link...)
 			insert := append([]string{string(Insert), "FORWARD"}, link...)
-			if output, err := Raw(insert...); err != nil {
+			if output, err := iptable.Raw(insert...); err != nil {
 				return err
 				return err
 			} else if len(output) != 0 {
 			} else if len(output) != 0 {
 				return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
 				return fmt.Errorf("Could not create linking rule to %s/%s: %s", c.Table, c.Name, output)
 			}
 			}
-		} else if Exists(Filter, "FORWARD", link...) && !enable {
+		} else if iptable.Exists(Filter, "FORWARD", link...) && !enable {
 			del := append([]string{string(Delete), "FORWARD"}, link...)
 			del := append([]string{string(Delete), "FORWARD"}, link...)
-			if output, err := Raw(del...); err != nil {
+			if output, err := iptable.Raw(del...); err != nil {
 				return err
 				return err
 			} else if len(output) != 0 {
 			} else if len(output) != 0 {
 				return fmt.Errorf("Could not delete linking rule from %s/%s: %s", c.Table, c.Name, output)
 				return fmt.Errorf("Could not delete linking rule from %s/%s: %s", c.Table, c.Name, output)
@@ -219,16 +257,16 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
 			"-m", "conntrack",
 			"-m", "conntrack",
 			"--ctstate", "RELATED,ESTABLISHED",
 			"--ctstate", "RELATED,ESTABLISHED",
 			"-j", "ACCEPT"}
 			"-j", "ACCEPT"}
-		if !Exists(Filter, "FORWARD", establish...) && enable {
+		if !iptable.Exists(Filter, "FORWARD", establish...) && enable {
 			insert := append([]string{string(Insert), "FORWARD"}, establish...)
 			insert := append([]string{string(Insert), "FORWARD"}, establish...)
-			if output, err := Raw(insert...); err != nil {
+			if output, err := iptable.Raw(insert...); err != nil {
 				return err
 				return err
 			} else if len(output) != 0 {
 			} else if len(output) != 0 {
 				return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output)
 				return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output)
 			}
 			}
-		} else if Exists(Filter, "FORWARD", establish...) && !enable {
+		} else if iptable.Exists(Filter, "FORWARD", establish...) && !enable {
 			del := append([]string{string(Delete), "FORWARD"}, establish...)
 			del := append([]string{string(Delete), "FORWARD"}, establish...)
-			if output, err := Raw(del...); err != nil {
+			if output, err := iptable.Raw(del...); err != nil {
 				return err
 				return err
 			} else if len(output) != 0 {
 			} else if len(output) != 0 {
 				return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output)
 				return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output)
@@ -239,10 +277,11 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
 }
 }
 
 
 // RemoveExistingChain removes existing chain from the table.
 // RemoveExistingChain removes existing chain from the table.
-func RemoveExistingChain(name string, table Table) error {
+func (iptable IPTable) RemoveExistingChain(name string, table Table) error {
 	c := &ChainInfo{
 	c := &ChainInfo{
-		Name:  name,
-		Table: table,
+		Name:    name,
+		Table:   table,
+		IPTable: iptable,
 	}
 	}
 	if string(c.Table) == "" {
 	if string(c.Table) == "" {
 		c.Table = Filter
 		c.Table = Filter
@@ -252,6 +291,8 @@ func RemoveExistingChain(name string, table Table) error {
 
 
 // Forward adds forwarding rule to 'filter' table and corresponding nat rule to 'nat' table.
 // Forward adds forwarding rule to 'filter' table and corresponding nat rule to 'nat' table.
 func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int, bridgeName string) error {
 func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr string, destPort int, bridgeName string) error {
+
+	iptable := GetIptable(c.IPTable.Version)
 	daddr := ip.String()
 	daddr := ip.String()
 	if ip.IsUnspecified() {
 	if ip.IsUnspecified() {
 		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
 		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
@@ -266,10 +307,11 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 		"--dport", strconv.Itoa(port),
 		"--dport", strconv.Itoa(port),
 		"-j", "DNAT",
 		"-j", "DNAT",
 		"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))}
 		"--to-destination", net.JoinHostPort(destAddr, strconv.Itoa(destPort))}
+
 	if !c.HairpinMode {
 	if !c.HairpinMode {
 		args = append(args, "!", "-i", bridgeName)
 		args = append(args, "!", "-i", bridgeName)
 	}
 	}
-	if err := ProgramRule(Nat, c.Name, action, args); err != nil {
+	if err := iptable.ProgramRule(Nat, c.Name, action, args); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -281,7 +323,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 		"--dport", strconv.Itoa(destPort),
 		"--dport", strconv.Itoa(destPort),
 		"-j", "ACCEPT",
 		"-j", "ACCEPT",
 	}
 	}
-	if err := ProgramRule(Filter, c.Name, action, args); err != nil {
+	if err := iptable.ProgramRule(Filter, c.Name, action, args); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -293,7 +335,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 		"-j", "MASQUERADE",
 		"-j", "MASQUERADE",
 	}
 	}
 
 
-	if err := ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
+	if err := iptable.ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
 		return err
 		return err
 	}
 	}
 
 
@@ -311,7 +353,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 			"-j", "CHECKSUM",
 			"-j", "CHECKSUM",
 			"--checksum-fill",
 			"--checksum-fill",
 		}
 		}
-		if err := ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
+		if err := iptable.ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -322,6 +364,7 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
 // Link adds reciprocal ACCEPT rule for two supplied IP addresses.
 // Link adds reciprocal ACCEPT rule for two supplied IP addresses.
 // Traffic is allowed from ip1 to ip2 and vice-versa
 // Traffic is allowed from ip1 to ip2 and vice-versa
 func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error {
 func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string, bridgeName string) error {
+	iptable := GetIptable(c.IPTable.Version)
 	// forward
 	// forward
 	args := []string{
 	args := []string{
 		"-i", bridgeName, "-o", bridgeName,
 		"-i", bridgeName, "-o", bridgeName,
@@ -331,32 +374,34 @@ func (c *ChainInfo) Link(action Action, ip1, ip2 net.IP, port int, proto string,
 		"--dport", strconv.Itoa(port),
 		"--dport", strconv.Itoa(port),
 		"-j", "ACCEPT",
 		"-j", "ACCEPT",
 	}
 	}
-	if err := ProgramRule(Filter, c.Name, action, args); err != nil {
+
+	if err := iptable.ProgramRule(Filter, c.Name, action, args); err != nil {
 		return err
 		return err
 	}
 	}
 	// reverse
 	// reverse
 	args[7], args[9] = args[9], args[7]
 	args[7], args[9] = args[9], args[7]
 	args[10] = "--sport"
 	args[10] = "--sport"
-	return ProgramRule(Filter, c.Name, action, args)
+	return iptable.ProgramRule(Filter, c.Name, action, args)
 }
 }
 
 
 // ProgramRule adds the rule specified by args only if the
 // ProgramRule adds the rule specified by args only if the
 // rule is not already present in the chain. Reciprocally,
 // rule is not already present in the chain. Reciprocally,
 // it removes the rule only if present.
 // it removes the rule only if present.
-func ProgramRule(table Table, chain string, action Action, args []string) error {
-	if Exists(table, chain, args...) != (action == Delete) {
+func (iptable IPTable) ProgramRule(table Table, chain string, action Action, args []string) error {
+	if iptable.Exists(table, chain, args...) != (action == Delete) {
 		return nil
 		return nil
 	}
 	}
-	return RawCombinedOutput(append([]string{"-t", string(table), string(action), chain}, args...)...)
+	return iptable.RawCombinedOutput(append([]string{"-t", string(table), string(action), chain}, args...)...)
 }
 }
 
 
 // Prerouting adds linking rule to nat/PREROUTING chain.
 // Prerouting adds linking rule to nat/PREROUTING chain.
 func (c *ChainInfo) Prerouting(action Action, args ...string) error {
 func (c *ChainInfo) Prerouting(action Action, args ...string) error {
+	iptable := GetIptable(c.IPTable.Version)
 	a := []string{"-t", string(Nat), string(action), "PREROUTING"}
 	a := []string{"-t", string(Nat), string(action), "PREROUTING"}
 	if len(args) > 0 {
 	if len(args) > 0 {
 		a = append(a, args...)
 		a = append(a, args...)
 	}
 	}
-	if output, err := Raw(a...); err != nil {
+	if output, err := iptable.Raw(a...); err != nil {
 		return err
 		return err
 	} else if len(output) != 0 {
 	} else if len(output) != 0 {
 		return ChainError{Chain: "PREROUTING", Output: output}
 		return ChainError{Chain: "PREROUTING", Output: output}
@@ -366,11 +411,12 @@ func (c *ChainInfo) Prerouting(action Action, args ...string) error {
 
 
 // Output adds linking rule to an OUTPUT chain.
 // Output adds linking rule to an OUTPUT chain.
 func (c *ChainInfo) Output(action Action, args ...string) error {
 func (c *ChainInfo) Output(action Action, args ...string) error {
+	iptable := GetIptable(c.IPTable.Version)
 	a := []string{"-t", string(c.Table), string(action), "OUTPUT"}
 	a := []string{"-t", string(c.Table), string(action), "OUTPUT"}
 	if len(args) > 0 {
 	if len(args) > 0 {
 		a = append(a, args...)
 		a = append(a, args...)
 	}
 	}
-	if output, err := Raw(a...); err != nil {
+	if output, err := iptable.Raw(a...); err != nil {
 		return err
 		return err
 	} else if len(output) != 0 {
 	} else if len(output) != 0 {
 		return ChainError{Chain: "OUTPUT", Output: output}
 		return ChainError{Chain: "OUTPUT", Output: output}
@@ -380,35 +426,36 @@ func (c *ChainInfo) Output(action Action, args ...string) error {
 
 
 // Remove removes the chain.
 // Remove removes the chain.
 func (c *ChainInfo) Remove() error {
 func (c *ChainInfo) Remove() error {
+	iptable := GetIptable(c.IPTable.Version)
 	// Ignore errors - This could mean the chains were never set up
 	// Ignore errors - This could mean the chains were never set up
 	if c.Table == Nat {
 	if c.Table == Nat {
 		c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name)
 		c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name)
-		c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8", "-j", c.Name)
+		c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", iptable.LoopbackByVersion(), "-j", c.Name)
 		c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name) // Created in versions <= 0.1.6
 		c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "-j", c.Name) // Created in versions <= 0.1.6
 
 
 		c.Prerouting(Delete)
 		c.Prerouting(Delete)
 		c.Output(Delete)
 		c.Output(Delete)
 	}
 	}
-	Raw("-t", string(c.Table), "-F", c.Name)
-	Raw("-t", string(c.Table), "-X", c.Name)
+	iptable.Raw("-t", string(c.Table), "-F", c.Name)
+	iptable.Raw("-t", string(c.Table), "-X", c.Name)
 	return nil
 	return nil
 }
 }
 
 
 // Exists checks if a rule exists
 // Exists checks if a rule exists
-func Exists(table Table, chain string, rule ...string) bool {
-	return exists(false, table, chain, rule...)
+func (iptable IPTable) Exists(table Table, chain string, rule ...string) bool {
+	return iptable.exists(false, table, chain, rule...)
 }
 }
 
 
 // ExistsNative behaves as Exists with the difference it
 // ExistsNative behaves as Exists with the difference it
 // will always invoke `iptables` binary.
 // will always invoke `iptables` binary.
-func ExistsNative(table Table, chain string, rule ...string) bool {
-	return exists(true, table, chain, rule...)
+func (iptable IPTable) ExistsNative(table Table, chain string, rule ...string) bool {
+	return iptable.exists(true, table, chain, rule...)
 }
 }
 
 
-func exists(native bool, table Table, chain string, rule ...string) bool {
-	f := Raw
+func (iptable IPTable) exists(native bool, table Table, chain string, rule ...string) bool {
+	f := iptable.Raw
 	if native {
 	if native {
-		f = raw
+		f = iptable.raw
 	}
 	}
 
 
 	if string(table) == "" {
 	if string(table) == "" {
@@ -429,12 +476,16 @@ func exists(native bool, table Table, chain string, rule ...string) bool {
 
 
 	// parse "iptables -S" for the rule (it checks rules in a specific chain
 	// parse "iptables -S" for the rule (it checks rules in a specific chain
 	// in a specific table and it is very unreliable)
 	// in a specific table and it is very unreliable)
-	return existsRaw(table, chain, rule...)
+	return iptable.existsRaw(table, chain, rule...)
 }
 }
 
 
-func existsRaw(table Table, chain string, rule ...string) bool {
+func (iptable IPTable) existsRaw(table Table, chain string, rule ...string) bool {
+	path := iptablesPath
+	if iptable.Version == IPv6 {
+		path = ip6tablesPath
+	}
 	ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
 	ruleString := fmt.Sprintf("%s %s\n", chain, strings.Join(rule, " "))
-	existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output()
+	existingRules, _ := exec.Command(path, "-t", string(table), "-S", chain).Output()
 
 
 	return strings.Contains(string(existingRules), ruleString)
 	return strings.Contains(string(existingRules), ruleString)
 }
 }
@@ -459,7 +510,7 @@ func filterOutput(start time.Time, output []byte, args ...string) []byte {
 }
 }
 
 
 // Raw calls 'iptables' system command, passing supplied arguments.
 // Raw calls 'iptables' system command, passing supplied arguments.
-func Raw(args ...string) ([]byte, error) {
+func (iptable IPTable) Raw(args ...string) ([]byte, error) {
 	if firewalldRunning {
 	if firewalldRunning {
 		startTime := time.Now()
 		startTime := time.Now()
 		output, err := Passthrough(Iptables, args...)
 		output, err := Passthrough(Iptables, args...)
@@ -467,10 +518,10 @@ func Raw(args ...string) ([]byte, error) {
 			return filterOutput(startTime, output, args...), err
 			return filterOutput(startTime, output, args...), err
 		}
 		}
 	}
 	}
-	return raw(args...)
+	return iptable.raw(args...)
 }
 }
 
 
-func raw(args ...string) ([]byte, error) {
+func (iptable IPTable) raw(args ...string) ([]byte, error) {
 	if err := initCheck(); err != nil {
 	if err := initCheck(); err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -481,10 +532,15 @@ func raw(args ...string) ([]byte, error) {
 		defer bestEffortLock.Unlock()
 		defer bestEffortLock.Unlock()
 	}
 	}
 
 
-	logrus.Debugf("%s, %v", iptablesPath, args)
+	path := iptablesPath
+	if iptable.Version == IPv6 {
+		path = ip6tablesPath
+	}
+
+	logrus.Debugf("%s, %v", path, args)
 
 
 	startTime := time.Now()
 	startTime := time.Now()
-	output, err := exec.Command(iptablesPath, args...).CombinedOutput()
+	output, err := exec.Command(path, args...).CombinedOutput()
 	if err != nil {
 	if err != nil {
 		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
 		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
 	}
 	}
@@ -494,8 +550,8 @@ func raw(args ...string) ([]byte, error) {
 
 
 // RawCombinedOutput internally calls the Raw function and returns a non nil
 // RawCombinedOutput internally calls the Raw function and returns a non nil
 // error if Raw returned a non nil error or a non empty output
 // error if Raw returned a non nil error or a non empty output
-func RawCombinedOutput(args ...string) error {
-	if output, err := Raw(args...); err != nil || len(output) != 0 {
+func (iptable IPTable) RawCombinedOutput(args ...string) error {
+	if output, err := iptable.Raw(args...); err != nil || len(output) != 0 {
 		return fmt.Errorf("%s (%v)", string(output), err)
 		return fmt.Errorf("%s (%v)", string(output), err)
 	}
 	}
 	return nil
 	return nil
@@ -503,16 +559,16 @@ func RawCombinedOutput(args ...string) error {
 
 
 // RawCombinedOutputNative behave as RawCombinedOutput with the difference it
 // RawCombinedOutputNative behave as RawCombinedOutput with the difference it
 // will always invoke `iptables` binary
 // will always invoke `iptables` binary
-func RawCombinedOutputNative(args ...string) error {
-	if output, err := raw(args...); err != nil || len(output) != 0 {
+func (iptable IPTable) RawCombinedOutputNative(args ...string) error {
+	if output, err := iptable.raw(args...); err != nil || len(output) != 0 {
 		return fmt.Errorf("%s (%v)", string(output), err)
 		return fmt.Errorf("%s (%v)", string(output), err)
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
 // ExistChain checks if a chain exists
 // ExistChain checks if a chain exists
-func ExistChain(chain string, table Table) bool {
-	if _, err := Raw("-t", string(table), "-nL", chain); err == nil {
+func (iptable IPTable) ExistChain(chain string, table Table) bool {
+	if _, err := iptable.Raw("-t", string(table), "-nL", chain); err == nil {
 		return true
 		return true
 	}
 	}
 	return false
 	return false
@@ -528,8 +584,8 @@ func GetVersion() (major, minor, micro int, err error) {
 }
 }
 
 
 // SetDefaultPolicy sets the passed default policy for the table/chain
 // SetDefaultPolicy sets the passed default policy for the table/chain
-func SetDefaultPolicy(table Table, chain string, policy Policy) error {
-	if err := RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
+func (iptable IPTable) SetDefaultPolicy(table Table, chain string, policy Policy) error {
+	if err := iptable.RawCombinedOutput("-t", string(table), "-P", chain, string(policy)); err != nil {
 		return fmt.Errorf("setting default policy to %v in %v chain failed: %v", policy, chain, err)
 		return fmt.Errorf("setting default policy to %v in %v chain failed: %v", policy, chain, err)
 	}
 	}
 	return nil
 	return nil
@@ -549,17 +605,17 @@ func supportsCOption(mj, mn, mc int) bool {
 }
 }
 
 
 // AddReturnRule adds a return rule for the chain in the filter table
 // AddReturnRule adds a return rule for the chain in the filter table
-func AddReturnRule(chain string) error {
+func (iptable IPTable) AddReturnRule(chain string) error {
 	var (
 	var (
 		table = Filter
 		table = Filter
 		args  = []string{"-j", "RETURN"}
 		args  = []string{"-j", "RETURN"}
 	)
 	)
 
 
-	if Exists(table, chain, args...) {
+	if iptable.Exists(table, chain, args...) {
 		return nil
 		return nil
 	}
 	}
 
 
-	err := RawCombinedOutput(append([]string{"-A", chain}, args...)...)
+	err := iptable.RawCombinedOutput(append([]string{"-A", chain}, args...)...)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error())
 		return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error())
 	}
 	}
@@ -568,20 +624,20 @@ func AddReturnRule(chain string) error {
 }
 }
 
 
 // EnsureJumpRule ensures the jump rule is on top
 // EnsureJumpRule ensures the jump rule is on top
-func EnsureJumpRule(fromChain, toChain string) error {
+func (iptable IPTable) EnsureJumpRule(fromChain, toChain string) error {
 	var (
 	var (
 		table = Filter
 		table = Filter
 		args  = []string{"-j", toChain}
 		args  = []string{"-j", toChain}
 	)
 	)
 
 
-	if Exists(table, fromChain, args...) {
-		err := RawCombinedOutput(append([]string{"-D", fromChain}, args...)...)
+	if iptable.Exists(table, fromChain, args...) {
+		err := iptable.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...)
 		if err != nil {
 		if err != nil {
 			return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
 			return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
 		}
 		}
 	}
 	}
 
 
-	err := RawCombinedOutput(append([]string{"-I", fromChain}, args...)...)
+	err := iptable.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...)
 	if err != nil {
 	if err != nil {
 		return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
 		return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error())
 	}
 	}

+ 2 - 2
vendor/github.com/docker/libnetwork/portmapper/mapper.go

@@ -151,7 +151,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
 	}
 	}
 
 
 	containerIP, containerPort := getIPAndPort(m.container)
 	containerIP, containerPort := getIPAndPort(m.container)
-	if hostIP.To4() != nil {
+	if hostIP.To4() != nil || hostIP.To16() != nil {
 		if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
 		if err := pm.AppendForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -160,7 +160,7 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
 	cleanup := func() error {
 	cleanup := func() error {
 		// need to undo the iptables rules before we return
 		// need to undo the iptables rules before we return
 		m.userlandProxy.Stop()
 		m.userlandProxy.Stop()
-		if hostIP.To4() != nil {
+		if hostIP.To4() != nil || hostIP.To16() != nil {
 			pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
 			pm.DeleteForwardingTableEntry(m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
 			if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 			if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
 				return err
 				return err

+ 12 - 9
vendor/github.com/docker/libnetwork/resolver_unix.go

@@ -57,25 +57,28 @@ func reexecSetupResolver() {
 		os.Exit(3)
 		os.Exit(3)
 	}
 	}
 
 
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+
 	// insert outputChain and postroutingchain
 	// insert outputChain and postroutingchain
-	err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
+	err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
 	if err == nil {
 	if err == nil {
-		iptables.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
 	} else {
 	} else {
-		iptables.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
-		iptables.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
 	}
 	}
 
 
-	err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
+	err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
 	if err == nil {
 	if err == nil {
-		iptables.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
 	} else {
 	} else {
-		iptables.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
-		iptables.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
+		iptable.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
 	}
 	}
 
 
 	for _, rule := range rules {
 	for _, rule := range rules {
-		if iptables.RawCombinedOutputNative(rule...) != nil {
+		if iptable.RawCombinedOutputNative(rule...) != nil {
 			logrus.Errorf("set up rule failed, %v", rule)
 			logrus.Errorf("set up rule failed, %v", rule)
 		}
 		}
 	}
 	}

+ 41 - 32
vendor/github.com/docker/libnetwork/service_linux.go

@@ -302,6 +302,9 @@ func filterPortConfigs(ingressPorts []*PortConfig, isDelete bool) []*PortConfig
 }
 }
 
 
 func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
 func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) error {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+
 	addDelOpt := "-I"
 	addDelOpt := "-I"
 	rollbackAddDelOpt := "-D"
 	rollbackAddDelOpt := "-D"
 	if isDelete {
 	if isDelete {
@@ -312,19 +315,19 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 	ingressMu.Lock()
 	ingressMu.Lock()
 	defer ingressMu.Unlock()
 	defer ingressMu.Unlock()
 
 
-	chainExists := iptables.ExistChain(ingressChain, iptables.Nat)
-	filterChainExists := iptables.ExistChain(ingressChain, iptables.Filter)
+	chainExists := iptable.ExistChain(ingressChain, iptables.Nat)
+	filterChainExists := iptable.ExistChain(ingressChain, iptables.Filter)
 
 
 	ingressOnce.Do(func() {
 	ingressOnce.Do(func() {
 		// Flush nat table and filter table ingress chain rules during init if it
 		// Flush nat table and filter table ingress chain rules during init if it
 		// exists. It might contain stale rules from previous life.
 		// exists. It might contain stale rules from previous life.
 		if chainExists {
 		if chainExists {
-			if err := iptables.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil {
+			if err := iptable.RawCombinedOutput("-t", "nat", "-F", ingressChain); err != nil {
 				logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err)
 				logrus.Errorf("Could not flush nat table ingress chain rules during init: %v", err)
 			}
 			}
 		}
 		}
 		if filterChainExists {
 		if filterChainExists {
-			if err := iptables.RawCombinedOutput("-F", ingressChain); err != nil {
+			if err := iptable.RawCombinedOutput("-F", ingressChain); err != nil {
 				logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err)
 				logrus.Errorf("Could not flush filter table ingress chain rules during init: %v", err)
 			}
 			}
 		}
 		}
@@ -332,38 +335,38 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 
 
 	if !isDelete {
 	if !isDelete {
 		if !chainExists {
 		if !chainExists {
-			if err := iptables.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil {
+			if err := iptable.RawCombinedOutput("-t", "nat", "-N", ingressChain); err != nil {
 				return fmt.Errorf("failed to create ingress chain: %v", err)
 				return fmt.Errorf("failed to create ingress chain: %v", err)
 			}
 			}
 		}
 		}
 		if !filterChainExists {
 		if !filterChainExists {
-			if err := iptables.RawCombinedOutput("-N", ingressChain); err != nil {
+			if err := iptable.RawCombinedOutput("-N", ingressChain); err != nil {
 				return fmt.Errorf("failed to create filter table ingress chain: %v", err)
 				return fmt.Errorf("failed to create filter table ingress chain: %v", err)
 			}
 			}
 		}
 		}
 
 
-		if !iptables.Exists(iptables.Nat, ingressChain, "-j", "RETURN") {
-			if err := iptables.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil {
+		if !iptable.Exists(iptables.Nat, ingressChain, "-j", "RETURN") {
+			if err := iptable.RawCombinedOutput("-t", "nat", "-A", ingressChain, "-j", "RETURN"); err != nil {
 				return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err)
 				return fmt.Errorf("failed to add return rule in nat table ingress chain: %v", err)
 			}
 			}
 		}
 		}
 
 
-		if !iptables.Exists(iptables.Filter, ingressChain, "-j", "RETURN") {
-			if err := iptables.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil {
+		if !iptable.Exists(iptables.Filter, ingressChain, "-j", "RETURN") {
+			if err := iptable.RawCombinedOutput("-A", ingressChain, "-j", "RETURN"); err != nil {
 				return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err)
 				return fmt.Errorf("failed to add return rule to filter table ingress chain: %v", err)
 			}
 			}
 		}
 		}
 
 
 		for _, chain := range []string{"OUTPUT", "PREROUTING"} {
 		for _, chain := range []string{"OUTPUT", "PREROUTING"} {
-			if !iptables.Exists(iptables.Nat, chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain) {
-				if err := iptables.RawCombinedOutput("-t", "nat", "-I", chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain); err != nil {
+			if !iptable.Exists(iptables.Nat, chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain) {
+				if err := iptable.RawCombinedOutput("-t", "nat", "-I", chain, "-m", "addrtype", "--dst-type", "LOCAL", "-j", ingressChain); err != nil {
 					return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err)
 					return fmt.Errorf("failed to add jump rule in %s to ingress chain: %v", chain, err)
 				}
 				}
 			}
 			}
 		}
 		}
 
 
-		if !iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
-			if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
+		if !iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
+			if err := iptable.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
 				return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err)
 				return fmt.Errorf("failed to add jump rule to %s in filter table forward chain: %v", ingressChain, err)
 			}
 			}
 			arrangeUserFilterRule()
 			arrangeUserFilterRule()
@@ -380,8 +383,8 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 		}
 		}
 
 
 		ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName))
 		ruleArgs := strings.Fields(fmt.Sprintf("-m addrtype --src-type LOCAL -o %s -j MASQUERADE", oifName))
-		if !iptables.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) {
-			if err := iptables.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil {
+		if !iptable.Exists(iptables.Nat, "POSTROUTING", ruleArgs...) {
+			if err := iptable.RawCombinedOutput(append([]string{"-t", "nat", "-I", "POSTROUTING"}, ruleArgs...)...); err != nil {
 				return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err)
 				return fmt.Errorf("failed to add ingress localhost POSTROUTING rule for %s: %v", oifName, err)
 			}
 			}
 		}
 		}
@@ -395,7 +398,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 		if portErr != nil && !isDelete {
 		if portErr != nil && !isDelete {
 			filterPortConfigs(filteredPorts, !isDelete)
 			filterPortConfigs(filteredPorts, !isDelete)
 			for _, rule := range rollbackRules {
 			for _, rule := range rollbackRules {
-				if err := iptables.RawCombinedOutput(rule...); err != nil {
+				if err := iptable.RawCombinedOutput(rule...); err != nil {
 					logrus.Warnf("roll back rule failed, %v: %v", rule, err)
 					logrus.Warnf("roll back rule failed, %v: %v", rule, err)
 				}
 				}
 			}
 			}
@@ -403,10 +406,10 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 	}()
 	}()
 
 
 	for _, iPort := range filteredPorts {
 	for _, iPort := range filteredPorts {
-		if iptables.ExistChain(ingressChain, iptables.Nat) {
+		if iptable.ExistChain(ingressChain, iptables.Nat) {
 			rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d",
 			rule := strings.Fields(fmt.Sprintf("-t nat %s %s -p %s --dport %d -j DNAT --to-destination %s:%d",
 				addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort))
 				addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort, gwIP, iPort.PublishedPort))
-			if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
+			if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
 				errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 				errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 				if !isDelete {
 				if !isDelete {
 					return fmt.Errorf("%s", errStr)
 					return fmt.Errorf("%s", errStr)
@@ -423,7 +426,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 		// 2) unmanaged containers on bridge networks
 		// 2) unmanaged containers on bridge networks
 		rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT",
 		rule := strings.Fields(fmt.Sprintf("%s %s -m state -p %s --sport %d --state ESTABLISHED,RELATED -j ACCEPT",
 			addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
 			addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
-		if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
+		if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
 			errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 			errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 			if !isDelete {
 			if !isDelete {
 				return fmt.Errorf("%s", errStr)
 				return fmt.Errorf("%s", errStr)
@@ -436,7 +439,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 
 
 		rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT",
 		rule = strings.Fields(fmt.Sprintf("%s %s -p %s --dport %d -j ACCEPT",
 			addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
 			addDelOpt, ingressChain, strings.ToLower(PortConfig_Protocol_name[int32(iPort.Protocol)]), iPort.PublishedPort))
-		if portErr = iptables.RawCombinedOutput(rule...); portErr != nil {
+		if portErr = iptable.RawCombinedOutput(rule...); portErr != nil {
 			errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 			errStr := fmt.Sprintf("set up rule failed, %v: %v", rule, portErr)
 			if !isDelete {
 			if !isDelete {
 				return fmt.Errorf("%s", errStr)
 				return fmt.Errorf("%s", errStr)
@@ -461,13 +464,15 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
 // This chain has the rules to allow access to the published ports for swarm tasks
 // This chain has the rules to allow access to the published ports for swarm tasks
 // from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
 // from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
 func arrangeIngressFilterRule() {
 func arrangeIngressFilterRule() {
-	if iptables.ExistChain(ingressChain, iptables.Filter) {
-		if iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
-			if err := iptables.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
+	if iptable.ExistChain(ingressChain, iptables.Filter) {
+		if iptable.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
+			if err := iptable.RawCombinedOutput("-D", "FORWARD", "-j", ingressChain); err != nil {
 				logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err)
 				logrus.Warnf("failed to delete jump rule to ingressChain in filter table: %v", err)
 			}
 			}
 		}
 		}
-		if err := iptables.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
+		if err := iptable.RawCombinedOutput("-I", "FORWARD", "-j", ingressChain); err != nil {
 			logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err)
 			logrus.Warnf("failed to add jump rule to ingressChain in filter table: %v", err)
 		}
 		}
 	}
 	}
@@ -606,6 +611,8 @@ func invokeFWMarker(path string, vip net.IP, fwMark uint32, ingressPorts []*Port
 
 
 // Firewall marker reexec function.
 // Firewall marker reexec function.
 func fwMarker() {
 func fwMarker() {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 	defer runtime.UnlockOSThread()
 
 
@@ -660,7 +667,7 @@ func fwMarker() {
 		}
 		}
 
 
 		ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP))
 		ruleParams := strings.Fields(fmt.Sprintf("-m ipvs --ipvs -d %s -j SNAT --to-source %s", subnet, eIP))
-		if !iptables.Exists("nat", "POSTROUTING", ruleParams...) {
+		if !iptable.Exists("nat", "POSTROUTING", ruleParams...) {
 			rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...)
 			rule := append(strings.Fields("-t nat -A POSTROUTING"), ruleParams...)
 			rules = append(rules, rule)
 			rules = append(rules, rule)
 
 
@@ -676,7 +683,7 @@ func fwMarker() {
 	rules = append(rules, rule)
 	rules = append(rules, rule)
 
 
 	for _, rule := range rules {
 	for _, rule := range rules {
-		if err := iptables.RawCombinedOutputNative(rule...); err != nil {
+		if err := iptable.RawCombinedOutputNative(rule...); err != nil {
 			logrus.Errorf("set up rule failed, %v: %v", rule, err)
 			logrus.Errorf("set up rule failed, %v: %v", rule, err)
 			os.Exit(8)
 			os.Exit(8)
 		}
 		}
@@ -711,6 +718,8 @@ func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) e
 
 
 // Redirector reexec function.
 // Redirector reexec function.
 func redirector() {
 func redirector() {
+	// TODO IPv6 support
+	iptable := iptables.GetIptable(iptables.IPv4)
 	runtime.LockOSThread()
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
 	defer runtime.UnlockOSThread()
 
 
@@ -763,7 +772,7 @@ func redirector() {
 	}
 	}
 
 
 	for _, rule := range rules {
 	for _, rule := range rules {
-		if err := iptables.RawCombinedOutputNative(rule...); err != nil {
+		if err := iptable.RawCombinedOutputNative(rule...); err != nil {
 			logrus.Errorf("set up rule failed, %v: %v", rule, err)
 			logrus.Errorf("set up rule failed, %v: %v", rule, err)
 			os.Exit(6)
 			os.Exit(6)
 		}
 		}
@@ -779,15 +788,15 @@ func redirector() {
 		{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
 		{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
 		{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
 		{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
 	} {
 	} {
-		if !iptables.ExistsNative(iptables.Filter, "INPUT", rule...) {
-			if err := iptables.RawCombinedOutputNative(append([]string{"-A", "INPUT"}, rule...)...); err != nil {
+		if !iptable.ExistsNative(iptables.Filter, "INPUT", rule...) {
+			if err := iptable.RawCombinedOutputNative(append([]string{"-A", "INPUT"}, rule...)...); err != nil {
 				logrus.Errorf("set up rule failed, %v: %v", rule, err)
 				logrus.Errorf("set up rule failed, %v: %v", rule, err)
 				os.Exit(7)
 				os.Exit(7)
 			}
 			}
 		}
 		}
 		rule[0] = "-s"
 		rule[0] = "-s"
-		if !iptables.ExistsNative(iptables.Filter, "OUTPUT", rule...) {
-			if err := iptables.RawCombinedOutputNative(append([]string{"-A", "OUTPUT"}, rule...)...); err != nil {
+		if !iptable.ExistsNative(iptables.Filter, "OUTPUT", rule...) {
+			if err := iptable.RawCombinedOutputNative(append([]string{"-A", "OUTPUT"}, rule...)...); err != nil {
 				logrus.Errorf("set up rule failed, %v: %v", rule, err)
 				logrus.Errorf("set up rule failed, %v: %v", rule, err)
 				os.Exit(8)
 				os.Exit(8)
 			}
 			}