diff --git a/hack/vendor.sh b/hack/vendor.sh index 32356d8be3..c3a9ccfa62 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -25,7 +25,7 @@ clone git github.com/docker/go-connections v0.1.2 clone git github.com/docker/engine-api v0.1.3 #get libnetwork packages -clone git github.com/docker/libnetwork 9f0563ea8f430d8828553aac97161cbff4056436 +clone git github.com/docker/libnetwork 49c24217054e269aad3dbfd81ee32780b104dd84 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 diff --git a/vendor/src/github.com/docker/libnetwork/README.md b/vendor/src/github.com/docker/libnetwork/README.md index cebf96af25..3f10a0311c 100644 --- a/vendor/src/github.com/docker/libnetwork/README.md +++ b/vendor/src/github.com/docker/libnetwork/README.md @@ -15,6 +15,11 @@ There are many networking solutions available to suit a broad range of use-cases ```go +func main() { + if reexec.Init() { + return + } + // Select and configure the network driver networkType := "bridge" @@ -24,14 +29,14 @@ There are many networking solutions available to suit a broad range of use-cases genericOption[netlabel.GenericData] = driverOptions controller, err := libnetwork.New(config.OptionDriverConfig(networkType, genericOption)) if err != nil { - return + log.Fatalf("libnetwork.New: %s", err) } // Create a network for containers to join. // NewNetwork accepts Variadic optional arguments that libnetwork and Drivers can use. network, err := controller.NewNetwork(networkType, "network1") if err != nil { - return + log.Fatalf("controller.NewNetwork: %s", err) } // For each new container: allocate IP and interfaces. The returned network @@ -40,7 +45,7 @@ There are many networking solutions available to suit a broad range of use-cases // from the returned endpoint. ep, err := network.CreateEndpoint("Endpoint1") if err != nil { - return + log.Fatalf("network.CreateEndpoint: %s", err) } // Create the sandbox for the container. @@ -48,22 +53,29 @@ There are many networking solutions available to suit a broad range of use-cases sbx, err := controller.NewSandbox("container1", libnetwork.OptionHostname("test"), libnetwork.OptionDomainname("docker.io")) + if err != nil { + log.Fatalf("controller.NewSandbox: %s", err) + } // A sandbox can join the endpoint via the join api. err = ep.Join(sbx) if err != nil { - return + log.Fatalf("ep.Join: %s", err) } // libnetwork client can check the endpoint's operational data via the Info() API epInfo, err := ep.DriverInfo() - mapData, ok := epInfo[netlabel.PortMap] - if ok { - portMapping, ok := mapData.([]types.PortBinding) - if ok { - fmt.Printf("Current port mapping for endpoint %s: %v", ep.Name(), portMapping) - } + if err != nil { + log.Fatalf("ep.DriverInfo: %s", err) } + + macAddress, ok := epInfo[netlabel.MacAddress] + if !ok { + log.Fatalf("failed to get mac address from endpoint info") + } + + fmt.Printf("Joined endpoint %s (%s) to sandbox %s (%s)\n", ep.Name(), macAddress, sbx.ContainerID(), sbx.Key()) +} ``` ## Future diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 04f5a4c81b..b2beef9ed6 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -106,12 +106,13 @@ type bridgeNetwork struct { } type driver struct { - config *configuration - network *bridgeNetwork - natChain *iptables.ChainInfo - filterChain *iptables.ChainInfo - networks map[string]*bridgeNetwork - store datastore.DataStore + config *configuration + network *bridgeNetwork + natChain *iptables.ChainInfo + filterChain *iptables.ChainInfo + isolationChain *iptables.ChainInfo + networks map[string]*bridgeNetwork + store datastore.DataStore sync.Mutex } @@ -244,15 +245,15 @@ func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) { n.iptCleanFuncs = append(n.iptCleanFuncs, clean) } -func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, error) { +func (n *bridgeNetwork) getDriverChains() (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) { n.Lock() defer n.Unlock() if n.driver == nil { - return nil, nil, types.BadRequestErrorf("no driver found") + return nil, nil, nil, types.BadRequestErrorf("no driver found") } - return n.driver.natChain, n.driver.filterChain, nil + return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain, nil } func (n *bridgeNetwork) getNetworkBridgeName() string { @@ -282,26 +283,16 @@ func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) { // from each of the other networks func (n *bridgeNetwork) isolateNetwork(others []*bridgeNetwork, enable bool) error { n.Lock() - thisV4 := n.bridge.bridgeIPv4 - thisV6 := getV6Network(n.config, n.bridge) + thisIface := n.config.BridgeName n.Unlock() // Install the rules to isolate this networks against each of the other networks for _, o := range others { o.Lock() - otherV4 := o.bridge.bridgeIPv4 - otherV6 := getV6Network(o.config, o.bridge) + otherIface := o.config.BridgeName o.Unlock() - - if !types.CompareIPNet(thisV4, otherV4) { - // It's ok to pass a.b.c.d/x, iptables will ignore the host subnet bits - if err := setINC(thisV4.String(), otherV4.String(), enable); err != nil { - return err - } - } - - if thisV6 != nil && otherV6 != nil && !types.CompareIPNet(thisV6, otherV6) { - if err := setINC(thisV6.String(), otherV6.String(), enable); err != nil { + if thisIface != otherIface { + if err := setINC(thisIface, otherIface, enable); err != nil { return err } } @@ -347,9 +338,11 @@ func (c *networkConfiguration) conflictsWithNetworks(id string, others []*bridge func (d *driver) configure(option map[string]interface{}) error { var ( - config *configuration - err error - natChain, filterChain *iptables.ChainInfo + config *configuration + err error + natChain *iptables.ChainInfo + filterChain *iptables.ChainInfo + isolationChain *iptables.ChainInfo ) genericData, ok := option[netlabel.GenericData] @@ -378,7 +371,7 @@ func (d *driver) configure(option map[string]interface{}) error { } if config.EnableIPTables { - natChain, filterChain, err = setupIPChains(config) + natChain, filterChain, isolationChain, err = setupIPChains(config) if err != nil { return err } @@ -387,6 +380,7 @@ func (d *driver) configure(option map[string]interface{}) error { d.Lock() d.natChain = natChain d.filterChain = filterChain + d.isolationChain = isolationChain d.config = config d.Unlock() diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go index 6b1c5dcb11..2d2442f295 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go @@ -11,35 +11,52 @@ import ( // DockerChain: DOCKER iptable chain name const ( - DockerChain = "DOCKER" + DockerChain = "DOCKER" + IsolationChain = "DOCKER-ISOLATION" ) -func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, error) { +func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) { // Sanity check. if config.EnableIPTables == false { - return nil, nil, fmt.Errorf("Cannot create new chains, EnableIPTable is disabled") + return nil, nil, nil, fmt.Errorf("cannot create new chains, EnableIPTable is disabled") } hairpinMode := !config.EnableUserlandProxy natChain, err := iptables.NewChain(DockerChain, iptables.Nat, hairpinMode) if err != nil { - return nil, nil, fmt.Errorf("Failed to create NAT chain: %s", err.Error()) + return nil, nil, nil, fmt.Errorf("failed to create NAT chain: %v", err) } defer func() { if err != nil { if err := iptables.RemoveExistingChain(DockerChain, iptables.Nat); err != nil { - logrus.Warnf("Failed on removing iptables NAT chain on cleanup: %v", err) + logrus.Warnf("failed on removing iptables NAT chain on cleanup: %v", err) } } }() - filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, hairpinMode) + filterChain, err := iptables.NewChain(DockerChain, iptables.Filter, false) if err != nil { - return nil, nil, fmt.Errorf("Failed to create FILTER chain: %s", err.Error()) + return nil, nil, nil, fmt.Errorf("failed to create FILTER chain: %v", err) + } + defer func() { + if err != nil { + if err := iptables.RemoveExistingChain(DockerChain, iptables.Filter); err != nil { + logrus.Warnf("failed on removing iptables FILTER chain on cleanup: %v", err) + } + } + }() + + isolationChain, err := iptables.NewChain(IsolationChain, iptables.Filter, false) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err) } - return natChain, filterChain, nil + if err := addReturnRule(IsolationChain); err != nil { + return nil, nil, nil, err + } + + return natChain, filterChain, isolationChain, nil } func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInterface) error { @@ -72,7 +89,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt return setupIPTablesInternal(config.BridgeName, maskedAddrv4, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false) }) - natChain, filterChain, err := n.getDriverChains() + natChain, filterChain, _, err := n.getDriverChains() if err != nil { return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error()) } @@ -86,6 +103,11 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt if err != nil { return fmt.Errorf("Failed to program FILTER chain: %s", err.Error()) } + + if err := ensureJumpRule("FORWARD", IsolationChain); err != nil { + return err + } + n.registerIptCleanFunc(func() error { return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false) }) @@ -166,10 +188,8 @@ func programChainRule(rule iptRule, ruleDescr string, insert bool) error { } if condition { - if output, err := iptables.Raw(append(prefix, rule.args...)...); err != nil { + if err := iptables.RawCombinedOutput(append(prefix, rule.args...)...); err != nil { return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error()) - } else if len(output) != 0 { - return &iptables.ChainError{Chain: rule.chain, Output: output} } } @@ -190,20 +210,16 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error { iptables.Raw(append([]string{"-D", chain}, acceptArgs...)...) if !iptables.Exists(table, chain, dropArgs...) { - if output, err := iptables.Raw(append([]string{"-A", chain}, dropArgs...)...); err != nil { + if err := iptables.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil { return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error()) - } else if len(output) != 0 { - return fmt.Errorf("Error disabling intercontainer communication: %s", output) } } } else { iptables.Raw(append([]string{"-D", chain}, dropArgs...)...) if !iptables.Exists(table, chain, acceptArgs...) { - if output, err := iptables.Raw(append([]string{"-I", chain}, acceptArgs...)...); err != nil { + if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil { return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error()) - } else if len(output) != 0 { - return fmt.Errorf("Error enabling intercontainer communication: %s", output) } } } @@ -224,11 +240,11 @@ func setIcc(bridgeIface string, iccEnable, insert bool) error { } // Control Inter Network Communication. Install/remove only if it is not/is present. -func setINC(network1, network2 string, enable bool) error { +func setINC(iface1, iface2 string, enable bool) error { var ( table = iptables.Filter - chain = "FORWARD" - args = [2][]string{{"-s", network1, "-d", network2, "-j", "DROP"}, {"-s", network2, "-d", network1, "-j", "DROP"}} + chain = IsolationChain + args = [2][]string{{"-i", iface1, "-o", iface2, "-j", "DROP"}, {"-i", iface2, "-o", iface1, "-j", "DROP"}} ) if enable { @@ -236,10 +252,8 @@ func setINC(network1, network2 string, enable bool) error { if iptables.Exists(table, chain, args[i]...) { continue } - if output, err := iptables.Raw(append([]string{"-I", chain}, args[i]...)...); err != nil { - return fmt.Errorf("unable to add inter-network communication rule: %s", err.Error()) - } else if len(output) != 0 { - return fmt.Errorf("error adding inter-network communication rule: %s", string(output)) + if err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args[i]...)...); err != nil { + return fmt.Errorf("unable to add inter-network communication rule: %v", err) } } } else { @@ -247,13 +261,51 @@ func setINC(network1, network2 string, enable bool) error { if !iptables.Exists(table, chain, args[i]...) { continue } - if output, err := iptables.Raw(append([]string{"-D", chain}, args[i]...)...); err != nil { - return fmt.Errorf("unable to remove inter-network communication rule: %s", err.Error()) - } else if len(output) != 0 { - return fmt.Errorf("error removing inter-network communication rule: %s", string(output)) + if err := iptables.RawCombinedOutput(append([]string{"-D", chain}, args[i]...)...); err != nil { + return fmt.Errorf("unable to remove inter-network communication rule: %v", err) } } } return nil } + +func addReturnRule(chain string) error { + var ( + table = iptables.Filter + args = []string{"-j", "RETURN"} + ) + + if iptables.Exists(table, chain, args...) { + return nil + } + + err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...) + if err != nil { + return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) + } + + return nil +} + +// Ensure the jump rule is on top +func ensureJumpRule(fromChain, toChain string) error { + var ( + table = iptables.Filter + args = []string{"-j", toChain} + ) + + if iptables.Exists(table, fromChain, args...) { + err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + } + + err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go index 0607548140..87b0c48aa0 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/filter.go @@ -12,16 +12,6 @@ const globalChain = "DOCKER-OVERLAY" var filterOnce sync.Once -func rawIPTables(args ...string) error { - if output, err := iptables.Raw(args...); err != nil { - return fmt.Errorf("unable to add overlay filter: %v", err) - } else if len(output) != 0 { - return fmt.Errorf("unable to add overlay filter: %s", string(output)) - } - - return nil -} - func chainExists(cname string) bool { if _, err := iptables.Raw("-L", cname); err != nil { return false @@ -31,12 +21,14 @@ func chainExists(cname string) bool { } func setupGlobalChain() { - if err := rawIPTables("-N", globalChain); err != nil { - logrus.Debugf("could not create global overlay chain: %v", err) + if err := iptables.RawCombinedOutput("-N", globalChain); err != nil { + logrus.Errorf("could not create global overlay chain: %v", err) + return } - if err := rawIPTables("-A", globalChain, "-j", "RETURN"); err != nil { - logrus.Debugf("could not install default return chain in the overlay global chain: %v", err) + if err := iptables.RawCombinedOutput("-A", globalChain, "-j", "RETURN"); err != nil { + logrus.Errorf("could not install default return chain in the overlay global chain: %v", err) + return } } @@ -49,21 +41,21 @@ func setNetworkChain(cname string, remove bool) error { opt := "-N" // In case of remove, make sure to flush the rules in the chain if remove && exists { - if err := rawIPTables("-F", cname); err != nil { + if err := iptables.RawCombinedOutput("-F", cname); err != nil { return fmt.Errorf("failed to flush overlay network chain %s rules: %v", cname, err) } opt = "-X" } if (!remove && !exists) || (remove && exists) { - if err := rawIPTables(opt, cname); err != nil { + if err := iptables.RawCombinedOutput(opt, cname); err != nil { return fmt.Errorf("failed network chain operation %q for chain %s: %v", opt, cname, err) } } if !remove { if !iptables.Exists(iptables.Filter, cname, "-j", "DROP") { - if err := rawIPTables("-A", cname, "-j", "DROP"); err != nil { + if err := iptables.RawCombinedOutput("-A", cname, "-j", "DROP"); err != nil { return fmt.Errorf("failed adding default drop rule to overlay network chain %s: %v", cname, err) } } @@ -91,12 +83,12 @@ func setFilters(cname, brName string, remove bool) error { for _, chain := range []string{"OUTPUT", "FORWARD"} { exists := iptables.Exists(iptables.Filter, chain, "-j", globalChain) if exists { - if err := rawIPTables("-D", chain, "-j", globalChain); err != nil { + if err := iptables.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) } } - if err := rawIPTables("-I", chain, "-j", globalChain); err != nil { + if err := iptables.RawCombinedOutput("-I", chain, "-j", globalChain); err != nil { return fmt.Errorf("failed to insert overlay hook in chain %s: %v", chain, err) } } @@ -105,7 +97,7 @@ func setFilters(cname, brName string, remove bool) error { // Insert/Delete the rule to jump to per-bridge chain exists := iptables.Exists(iptables.Filter, globalChain, "-o", brName, "-j", cname) if (!remove && !exists) || (remove && exists) { - if err := rawIPTables(opt, globalChain, "-o", brName, "-j", cname); err != nil { + if err := iptables.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) } } @@ -115,7 +107,7 @@ func setFilters(cname, brName string, remove bool) error { return nil } - if err := rawIPTables(opt, cname, "-i", brName, "-j", "ACCEPT"); err != nil { + if err := iptables.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) } diff --git a/vendor/src/github.com/docker/libnetwork/endpoint.go b/vendor/src/github.com/docker/libnetwork/endpoint.go index d5f38c51a2..b0eed2b626 100644 --- a/vendor/src/github.com/docker/libnetwork/endpoint.go +++ b/vendor/src/github.com/docker/libnetwork/endpoint.go @@ -61,6 +61,7 @@ type endpoint struct { generic map[string]interface{} joinLeaveDone chan struct{} prefAddress net.IP + prefAddressV6 net.IP ipamOptions map[string]string dbIndex uint64 dbExists bool @@ -688,9 +689,10 @@ func EndpointOptionGeneric(generic map[string]interface{}) EndpointOption { } // CreateOptionIpam function returns an option setter for the ipam configuration for this endpoint -func CreateOptionIpam(prefAddress net.IP, ipamOptions map[string]string) EndpointOption { +func CreateOptionIpam(ipV4, ipV6 net.IP, ipamOptions map[string]string) EndpointOption { return func(ep *endpoint) { - ep.prefAddress = prefAddress + ep.prefAddress = ipV4 + ep.prefAddressV6 = ipV6 ep.ipamOptions = ipamOptions } } @@ -775,6 +777,8 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { var ( poolID *string address **net.IPNet + prefAdd net.IP + progAdd net.IP ) n := ep.getNetwork() @@ -782,9 +786,11 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { case 4: poolID = &ep.iface.v4PoolID address = &ep.iface.addr + prefAdd = ep.prefAddress case 6: poolID = &ep.iface.v6PoolID address = &ep.iface.addrv6 + prefAdd = ep.prefAddressV6 default: return types.InternalErrorf("incorrect ip version number passed: %d", ipVer) } @@ -796,12 +802,19 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { return nil } + // The address to program may be chosen by the user or by the network driver in one specific + // case to support backward compatibility with `docker daemon --fixed-cidrv6` use case + if prefAdd != nil { + progAdd = prefAdd + } else if *address != nil { + progAdd = (*address).IP + } + for _, d := range ipInfo { - var prefIP net.IP - if *address != nil { - prefIP = (*address).IP + if progAdd != nil && !d.Pool.Contains(progAdd) { + continue } - addr, _, err := ipam.RequestAddress(d.PoolID, prefIP, ep.ipamOptions) + addr, _, err := ipam.RequestAddress(d.PoolID, progAdd, ep.ipamOptions) if err == nil { ep.Lock() *address = addr @@ -809,10 +822,13 @@ func (ep *endpoint) assignAddressVersion(ipVer int, ipam ipamapi.Ipam) error { ep.Unlock() return nil } - if err != ipamapi.ErrNoAvailableIPs { + if err != ipamapi.ErrNoAvailableIPs || progAdd != nil { return err } } + if progAdd != nil { + return types.BadRequestErrorf("Invalid preferred address %s: It does not belong to any of this network's subnets") + } return fmt.Errorf("no available IPv%d addresses on this network's address pools: %s (%s)", ipVer, n.Name(), n.ID()) } diff --git a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go index be7725f85d..170ea1353e 100644 --- a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go +++ b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go @@ -312,6 +312,7 @@ func Exists(table Table, chain string, rule ...string) bool { // parse "iptables -S" for the rule (this checks rules in a specific chain // in a specific table) ruleString := strings.Join(rule, " ") + ruleString = chain + " " + ruleString existingRules, _ := exec.Command(iptablesPath, "-t", string(table), "-S", chain).Output() return strings.Contains(string(existingRules), ruleString) @@ -351,3 +352,12 @@ func Raw(args ...string) ([]byte, error) { return output, err } + +// RawCombinedOutput inernally calls the Raw function and returns a non nil +// 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 { + return fmt.Errorf("%s (%v)", string(output), err) + } + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go b/vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go index f981b1fc85..6c6dac589f 100644 --- a/vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go +++ b/vendor/src/github.com/docker/libnetwork/resolvconf/dns/resolvconf.go @@ -5,7 +5,7 @@ import ( ) // IPLocalhost is a regex patter for localhost IP address range. -const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1))` +const IPLocalhost = `((127\.([0-9]{1,3}\.){2}[0-9]{1,3})|(::1)$)` var localhostIPRegexp = regexp.MustCompile(IPLocalhost)