Skip to content

Commit

Permalink
Warn if a docker network config can cause issues on macOS (hyperledge…
Browse files Browse the repository at this point in the history
…r#1115)

The default docker local network address pool includes addresses that
are commonly used on home networks. This configuration can prevent
containers from accessing the network host on the LAN addresses
discovered by the peer. This often surfaces in integration tests as
chaincode registration failures with a "no route to host" message.

This change attempts to discover and highlight the broken configuration
so that it can be addressed. (pun, heh)

The network pools can be configured by adding some JSON to the Docker
daemon configuration to prevent the overlaps. The comment near the
warning message describes the syntax.

Change-Id: I11b5ad72df497053dc2a07f68b6370b06679d995
Signed-off-by: Matthew Sykes <sykesmat@us.ibm.com>
  • Loading branch information
sykesm authored Apr 17, 2020
1 parent 65d3817 commit 1559374
Showing 1 changed file with 88 additions and 7 deletions.
95 changes: 88 additions & 7 deletions integration/nwo/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -662,13 +664,7 @@ func (n *Network) GenerateConfigTree() {
// written to ${rootDir}/${Channel.Name}_tx.pb.
func (n *Network) Bootstrap() {
if n.DockerClient != nil {
_, err := n.DockerClient.CreateNetwork(
docker.CreateNetworkOptions{
Name: n.NetworkID,
Driver: "bridge",
},
)
Expect(err).NotTo(HaveOccurred())
n.createDockerNetwork()
}

sess, err := n.Cryptogen(commands.Generate{
Expand Down Expand Up @@ -704,6 +700,91 @@ func (n *Network) Bootstrap() {
n.ConcatenateTLSCACertificates()
}

func (n *Network) createDockerNetwork() {
_, err := n.DockerClient.CreateNetwork(
docker.CreateNetworkOptions{
Name: n.NetworkID,
Driver: "bridge",
},
)
Expect(err).NotTo(HaveOccurred())

if runtime.GOOS == "darwin" {
n.checkDockerNetworks()
}
}

// checkDockerNetworks attempts to discover if the docker network configuration
// will prevent a container from accessing the host. This commonly happens when
// using Docker for Mac on home networks because most home routers provide DHCP
// addresses from 192.168.1.0/24 and the default Docker daemon config uses
// 192.168.0.0/20 as one of the default local address pools.
//
// https://github.com/moby/libnetwork/blob/1a17fb36132631a95fe6bb055b91e24a516ad81d/ipamutils/utils.go#L18-L20
//
// Docker can be configured to use different addresses by addding an
// appropriate default-address-pools configuration element to "daemon.json".
//
// For example:
// "default-address-pools":[
// {"base":"172.80.0.0/16","size":24},
// {"base":"172.81.0.0/16","size":24}
// ]
func (n *Network) checkDockerNetworks() {
hostAddrs := hostIPv4Addrs()
for _, nw := range n.dockerIPNets() {
for _, a := range hostAddrs {
if nw.Contains(a) {
fmt.Fprintf(ginkgo.GinkgoWriter, "\x1b[01;37;41mWARNING: docker network %s overlaps with host address %s.\x1b[0m\n", nw, a)
fmt.Fprintf(ginkgo.GinkgoWriter, "\x1b[01;37;41mDocker containers may not have connectivity causing chaincode registration to fail with 'no route to host'.\x1b[0m\n")
}
}
}
}

func (n *Network) dockerIPNets() []*net.IPNet {
dockerNetworks, err := n.DockerClient.ListNetworks()
Expect(err).NotTo(HaveOccurred())

var nets []*net.IPNet
for _, nw := range dockerNetworks {
for _, ipconf := range nw.IPAM.Config {
if ipconf.Subnet != "" {
_, ipn, err := net.ParseCIDR(ipconf.Subnet)
Expect(err).NotTo(HaveOccurred())
nets = append(nets, ipn)
}
}
}
return nets
}

func hostIPv4Addrs() []net.IP {
interfaces, err := net.Interfaces()
Expect(err).NotTo(HaveOccurred())

var addresses []net.IP
for _, i := range interfaces {
addrs, err := i.Addrs()
Expect(err).NotTo(HaveOccurred())

for _, a := range addrs {
a := a
switch v := a.(type) {
case *net.IPAddr:
if v.IP.To4() != nil {
addresses = append(addresses, v.IP)
}
case *net.IPNet:
if v.IP.To4() != nil {
addresses = append(addresses, v.IP)
}
}
}
}
return addresses
}

// bootstrapIdemix creates the idemix-related crypto material
func (n *Network) bootstrapIdemix() {
for j, org := range n.IdemixOrgs() {
Expand Down

0 comments on commit 1559374

Please sign in to comment.