From a0c213f90c28537f7857b647e9ad9bb6e6141c4b Mon Sep 17 00:00:00 2001 From: Chris Telfer Date: Fri, 29 Jun 2018 10:38:44 -0400 Subject: [PATCH 1/2] bump libnetwork to 430c00a Bump libnetwork to 430c00a6a6b3dfdd774f21e1abd4ad6b0216c629. This includes the following moby-affecting changes: * Update vendoring for go-sockaddr (8df9f31a) * Fix inconsistent subnet allocation by preventing allocation of overlapping subnets (8579c5d2) * Handle IPv6 literals correctly in port bindings (474fcaf4) * Update vendoring for miekg/dns (8f307ac8) * Avoid subnet reallocation until required (9756ff7ed) * Bump libnetwork build to use go version 1.10.2 (603d2c1a) * Unwrap error type returned by PluginGetter (aacec8e1) * Update vendored components to match moby (d768021dd) * Add retry field to cluster-peers probe (dbbd06a7) * Fix net driver response loss on createEndpoint (1ab6e506) (fixes https://github.com/docker/for-linux/issues/348) Signed-off-by: Chris Telfer (cherry picked from commit f155f828a26cfb3ee0dd8ca48bd2c702c9032b0b) Signed-off-by: Sebastiaan van Stijn --- hack/dockerfile/install/proxy.installer | 2 +- vendor.conf | 4 +- .../docker/libnetwork/controller.go | 3 +- .../docker/libnetwork/ipam/allocator.go | 42 ++- .../docker/libnetwork/ipam/structures.go | 7 +- .../github.com/docker/libnetwork/network.go | 17 +- .../docker/libnetwork/networkdb/delegate.go | 2 +- .../docker/libnetwork/types/types.go | 25 +- .../github.com/docker/libnetwork/vendor.conf | 51 ++- .../hashicorp/go-sockaddr/ifaddr.go | 128 +++++++ .../hashicorp/go-sockaddr/ifaddrs.go | 342 +++++++++++++++++- .../hashicorp/go-sockaddr/ipv4addr.go | 3 +- .../github.com/hashicorp/go-sockaddr/rfc.go | 1 + .../hashicorp/go-sockaddr/route_info_linux.go | 15 +- .../hashicorp/go-sockaddr/sockaddr.go | 28 ++ 15 files changed, 592 insertions(+), 78 deletions(-) diff --git a/hack/dockerfile/install/proxy.installer b/hack/dockerfile/install/proxy.installer index 00c2f1dd05e06..b5748b51a886f 100755 --- a/hack/dockerfile/install/proxy.installer +++ b/hack/dockerfile/install/proxy.installer @@ -3,7 +3,7 @@ # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When # updating the binary version, consider updating github.com/docker/libnetwork # in vendor.conf accordingly -LIBNETWORK_COMMIT=19279f0492417475b6bfbd0aa529f73e8f178fb5 +LIBNETWORK_COMMIT=430c00a6a6b3dfdd774f21e1abd4ad6b0216c629 install_proxy() { case "$1" in diff --git a/vendor.conf b/vendor.conf index cd059b719e248..5327c9d194129 100644 --- a/vendor.conf +++ b/vendor.conf @@ -37,14 +37,14 @@ github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b #get libnetwork packages # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly -github.com/docker/libnetwork 19279f0492417475b6bfbd0aa529f73e8f178fb5 +github.com/docker/libnetwork 430c00a6a6b3dfdd774f21e1abd4ad6b0216c629 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 -github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d +github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9 github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef diff --git a/vendor/github.com/docker/libnetwork/controller.go b/vendor/github.com/docker/libnetwork/controller.go index fe9c4ddf97ecf..5e967b7c32771 100644 --- a/vendor/github.com/docker/libnetwork/controller.go +++ b/vendor/github.com/docker/libnetwork/controller.go @@ -69,6 +69,7 @@ import ( "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/osl" "github.com/docker/libnetwork/types" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -1252,7 +1253,7 @@ func (c *controller) loadDriver(networkType string) error { } if err != nil { - if err == plugins.ErrNotFound { + if errors.Cause(err) == plugins.ErrNotFound { return types.NotFoundErrorf(err.Error()) } return err diff --git a/vendor/github.com/docker/libnetwork/ipam/allocator.go b/vendor/github.com/docker/libnetwork/ipam/allocator.go index 29473c5cc3224..7213148bcca88 100644 --- a/vendor/github.com/docker/libnetwork/ipam/allocator.go +++ b/vendor/github.com/docker/libnetwork/ipam/allocator.go @@ -29,7 +29,10 @@ const ( // Allocator provides per address space ipv4/ipv6 book keeping type Allocator struct { // Predefined pools for default address spaces - predefined map[string][]*net.IPNet + // Separate from the addrSpace because they should not be serialized + predefined map[string][]*net.IPNet + predefinedStartIndices map[string]int + // The (potentially serialized) address spaces addrSpaces map[string]*addrSpace // stores []datastore.Datastore // Allocated addresses in each address space's subnet @@ -47,6 +50,9 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) { globalAddressSpace: ipamutils.PredefinedGranularNetworks, } + // Initialize asIndices map + a.predefinedStartIndices = make(map[string]int) + // Initialize bitseq map a.addresses = make(map[SubnetKey]*bitseq.Handle) @@ -374,11 +380,24 @@ func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, func (a *Allocator) getPredefineds(as string) []*net.IPNet { a.Lock() defer a.Unlock() - l := make([]*net.IPNet, 0, len(a.predefined[as])) - for _, pool := range a.predefined[as] { - l = append(l, pool) + + p := a.predefined[as] + i := a.predefinedStartIndices[as] + // defensive in case the list changed since last update + if i >= len(p) { + i = 0 } - return l + return append(p[i:], p[:i]...) +} + +func (a *Allocator) updateStartIndex(as string, amt int) { + a.Lock() + i := a.predefinedStartIndices[as] + amt + if i < 0 || i >= len(a.predefined[as]) { + i = 0 + } + a.predefinedStartIndices[as] = i + a.Unlock() } func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) { @@ -397,21 +416,26 @@ func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) return nil, err } - for _, nw := range a.getPredefineds(as) { + predefined := a.getPredefineds(as) + + aSpace.Lock() + for i, nw := range predefined { if v != getAddressVersion(nw.IP) { continue } - aSpace.Lock() + // Checks whether pool has already been allocated if _, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]; ok { - aSpace.Unlock() continue } + // Shouldn't be necessary, but check prevents IP collisions should + // predefined pools overlap for any reason. if !aSpace.contains(as, nw) { aSpace.Unlock() + a.updateStartIndex(as, i+1) return nw, nil } - aSpace.Unlock() } + aSpace.Unlock() return nil, types.NotFoundErrorf("could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network", v) } diff --git a/vendor/github.com/docker/libnetwork/ipam/structures.go b/vendor/github.com/docker/libnetwork/ipam/structures.go index 09a77695dd4f3..455a16ca650a0 100644 --- a/vendor/github.com/docker/libnetwork/ipam/structures.go +++ b/vendor/github.com/docker/libnetwork/ipam/structures.go @@ -262,12 +262,13 @@ func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *Addr defer aSpace.Unlock() // Check if already allocated - if p, ok := aSpace.subnets[k]; ok { + if _, ok := aSpace.subnets[k]; ok { if pdf { return nil, types.InternalMaskableErrorf("predefined pool %s is already reserved", nw) } - aSpace.incRefCount(p, 1) - return func() error { return nil }, nil + // This means the same pool is already allocated. updatePoolDBOnAdd is called when there + // is request for a pool/subpool. It should ensure there is no overlap with existing pools + return nil, ipamapi.ErrPoolOverlap } // If master pool, check for overlap diff --git a/vendor/github.com/docker/libnetwork/network.go b/vendor/github.com/docker/libnetwork/network.go index e283d658153ea..70d6b1cc696ff 100644 --- a/vendor/github.com/docker/libnetwork/network.go +++ b/vendor/github.com/docker/libnetwork/network.go @@ -1156,26 +1156,27 @@ func (n *network) createEndpoint(name string, options ...EndpointOption) (Endpoi ep.releaseAddress() } }() - // Moving updateToSTore before calling addEndpoint so that we shall clean up VETH interfaces in case - // DockerD get killed between addEndpoint and updateSTore call - if err = n.getController().updateToStore(ep); err != nil { + + if err = n.addEndpoint(ep); err != nil { return nil, err } defer func() { if err != nil { - if e := n.getController().deleteFromStore(ep); e != nil { - logrus.Warnf("error rolling back endpoint %s from store: %v", name, e) + if e := ep.deleteEndpoint(false); e != nil { + logrus.Warnf("cleaning up endpoint failed %s : %v", name, e) } } }() - if err = n.addEndpoint(ep); err != nil { + // We should perform updateToStore call right after addEndpoint + // in order to have iface properly configured + if err = n.getController().updateToStore(ep); err != nil { return nil, err } defer func() { if err != nil { - if e := ep.deleteEndpoint(false); e != nil { - logrus.Warnf("cleaning up endpoint failed %s : %v", name, e) + if e := n.getController().deleteFromStore(ep); e != nil { + logrus.Warnf("error rolling back endpoint %s from store: %v", name, e) } } }() diff --git a/vendor/github.com/docker/libnetwork/networkdb/delegate.go b/vendor/github.com/docker/libnetwork/networkdb/delegate.go index 9a379fe7cdb20..6cd827ee26240 100644 --- a/vendor/github.com/docker/libnetwork/networkdb/delegate.go +++ b/vendor/github.com/docker/libnetwork/networkdb/delegate.go @@ -41,7 +41,7 @@ func (nDB *NetworkDB) handleNodeEvent(nEvent *NodeEvent) bool { // If the node is not known from memberlist we cannot process save any state of it else if it actually // dies we won't receive any notification and we will remain stuck with it if _, ok := nDB.nodes[nEvent.NodeName]; !ok { - logrus.Error("node: %s is unknown to memberlist", nEvent.NodeName) + logrus.Errorf("node: %s is unknown to memberlist", nEvent.NodeName) return false } diff --git a/vendor/github.com/docker/libnetwork/types/types.go b/vendor/github.com/docker/libnetwork/types/types.go index f851d6fbb7c45..5968545ba5143 100644 --- a/vendor/github.com/docker/libnetwork/types/types.go +++ b/vendor/github.com/docker/libnetwork/types/types.go @@ -145,7 +145,12 @@ func (p *PortBinding) String() string { return ret } -// FromString reads the PortBinding structure from string +// FromString reads the PortBinding structure from string s. +// String s is a triple of "protocol/containerIP:port/hostIP:port" +// containerIP and hostIP can be in dotted decimal ("192.0.2.1") or IPv6 ("2001:db8::68") form. +// Zoned addresses ("169.254.0.23%eth0" or "fe80::1ff:fe23:4567:890a%eth0") are not supported. +// If string s is incorrectly formatted or the IP addresses or ports cannot be parsed, FromString +// returns an error. func (p *PortBinding) FromString(s string) error { ps := strings.Split(s, "/") if len(ps) != 3 { @@ -167,21 +172,19 @@ func (p *PortBinding) FromString(s string) error { } func parseIPPort(s string) (net.IP, uint16, error) { - pp := strings.Split(s, ":") - if len(pp) != 2 { - return nil, 0, BadRequestErrorf("invalid format: %s", s) + hoststr, portstr, err := net.SplitHostPort(s) + if err != nil { + return nil, 0, err } - var ip net.IP - if pp[0] != "" { - if ip = net.ParseIP(pp[0]); ip == nil { - return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0]) - } + ip := net.ParseIP(hoststr) + if ip == nil { + return nil, 0, BadRequestErrorf("invalid ip: %s", hoststr) } - port, err := strconv.ParseUint(pp[1], 10, 16) + port, err := strconv.ParseUint(portstr, 10, 16) if err != nil { - return nil, 0, BadRequestErrorf("invalid port: %s", pp[1]) + return nil, 0, BadRequestErrorf("invalid port: %s", portstr) } return ip, uint16(port), nil diff --git a/vendor/github.com/docker/libnetwork/vendor.conf b/vendor/github.com/docker/libnetwork/vendor.conf index 9480699b87cd0..5237c5588a522 100644 --- a/vendor/github.com/docker/libnetwork/vendor.conf +++ b/vendor/github.com/docker/libnetwork/vendor.conf @@ -1,27 +1,28 @@ github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 -github.com/Microsoft/go-winio v0.4.5 -github.com/Microsoft/hcsshim v0.6.5 +github.com/Microsoft/go-winio v0.4.7 +github.com/Microsoft/hcsshim v0.6.11 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904 -github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e -github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8 +github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925 +github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b github.com/coreos/etcd v3.2.1 github.com/coreos/go-semver v0.2.0 -github.com/coreos/go-systemd v4 +github.com/coreos/go-systemd v17 +github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d -github.com/docker/docker a3efe9722f34af5cf4443fe3a5c4e4e3e0457b54 -github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d +github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149 +github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef github.com/godbus/dbus v4.0.0 -github.com/gogo/protobuf v0.4 -github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 +github.com/gogo/protobuf v1.0.0 +github.com/golang/protobuf v1.1.0 github.com/gorilla/context v1.1 github.com/gorilla/mux v1.1 github.com/hashicorp/consul v0.5.2 @@ -29,27 +30,37 @@ github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 -github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d +github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 github.com/mattn/go-shellwords v1.0.3 -github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 +github.com/miekg/dns v1.0.7 github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08 -github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb -github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 -github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d -github.com/opencontainers/runtime-spec v1.0.0 -github.com/opencontainers/selinux v1.0.0-rc1 +github.com/opencontainers/go-digest v1.0.0-rc1 +github.com/opencontainers/image-spec v1.0.1 +github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340 +github.com/opencontainers/runtime-spec v1.0.1 +github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 github.com/sirupsen/logrus v1.0.3 github.com/stretchr/testify dab07ac62d4905d3e48d17dc549c684ac3b7c15a -github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16 +github.com/syndtr/gocapability 33e07d32887e1e06b7c025f27ce52f62c7990bc0 github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065 github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 -golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca -golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac -golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5 +golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491 +golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd +golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb + +github.com/davecgh/go-spew 8991bc29aa16c548c550c7ff78260e27b9ab7c73 +github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2 +github.com/cyphar/filepath-securejoin v0.2.1 +github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 +github.com/hashicorp/go-immutable-radix 7f3cd4390caab3250a57f30efdb2a65dd7649ecf +github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3 +github.com/hashicorp/go-cleanhttp d5fe4b57a186c716b0e00b8c301cbd9b4182694d +github.com/hashicorp/go-rootcerts 6bb64b370b90e7ef1fa532be9e591a81c3493e00 +github.com/mitchellh/go-homedir 3864e76763d94a6df2f9960b16a20a33da9f9a66 diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go index 3e4ff9fca433b..0811b27599056 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go @@ -1,5 +1,7 @@ package sockaddr +import "strings" + // ifAddrAttrMap is a map of the IfAddr type-specific attributes. var ifAddrAttrMap map[AttrName]func(IfAddr) string var ifAddrAttrs []AttrName @@ -30,6 +32,53 @@ func GetPrivateIP() (string, error) { return ip.NetIP().String(), nil } +// GetPrivateIPs returns a string with all IP addresses that are part of RFC +// 6890 (regardless of whether or not there is a default route, unlike +// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty +// string will be returned instead. This function is the `eval` equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}' +/// ``` +func GetPrivateIPs() (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } else if len(ifAddrs) < 1 { + return "", nil + } + + ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) + if len(ifAddrs) == 0 { + return "", nil + } + + OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) + + ifAddrs, _, err = IfByRFC("6890", ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + // GetPublicIP returns a string with a single IP address that is NOT part of RFC // 6890 and has a default route. If the system can't determine its IP address // or find a non RFC 6890 IP address, an empty string will be returned instead. @@ -51,6 +100,47 @@ func GetPublicIP() (string, error) { return ip.NetIP().String(), nil } +// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC +// 6890 (regardless of whether or not there is a default route, unlike +// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an +// empty string will be returned instead. This function is the `eval` +// equivalent of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}' +/// ``` +func GetPublicIPs() (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } else if len(ifAddrs) < 1 { + return "", nil + } + + ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) + if len(ifAddrs) == 0 { + return "", nil + } + + OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) + + _, ifAddrs, err = IfByRFC("6890", ifAddrs) + if err != nil { + return "", err + } else if len(ifAddrs) == 0 { + return "", nil + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + // GetInterfaceIP returns a string with a single IP address sorted by the size // of the network (i.e. IP addresses with a smaller netmask, larger network // size, are sorted first). This function is the `eval` equivalent of: @@ -91,6 +181,44 @@ func GetInterfaceIP(namedIfRE string) (string, error) { return IPAddrAttr(*ip, "address"), nil } +// GetInterfaceIPs returns a string with all IPs, sorted by the size of the +// network (i.e. IP addresses with a smaller netmask, larger network size, are +// sorted first), on a named interface. This function is the `eval` equivalent +// of: +// +// ``` +// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}' +/// ``` +func GetInterfaceIPs(namedIfRE string) (string, error) { + ifAddrs, err := GetAllInterfaces() + if err != nil { + return "", err + } + + ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) + if err != nil { + return "", err + } + + ifAddrs, err = SortIfBy("+type,+size", ifAddrs) + if err != nil { + return "", err + } + + if len(ifAddrs) == 0 { + return "", err + } + + ips := make([]string, 0, len(ifAddrs)) + for _, ifAddr := range ifAddrs { + ip := *ToIPAddr(ifAddr.SockAddr) + s := ip.NetIP().String() + ips = append(ips, s) + } + + return strings.Join(ips, " "), nil +} + // IfAddrAttrs returns a list of attributes supported by the IfAddr type func IfAddrAttrs() []AttrName { return ifAddrAttrs diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go index 8233be2022bf5..2a706c34e92b8 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go @@ -1,8 +1,10 @@ package sockaddr import ( + "encoding/binary" "errors" "fmt" + "math/big" "net" "regexp" "sort" @@ -10,6 +12,14 @@ import ( "strings" ) +var ( + // Centralize all regexps and regexp.Copy() where necessary. + signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`) + whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`) + ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`) + ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) +) + // IfAddrs is a slice of IfAddr type IfAddrs []IfAddr @@ -91,6 +101,40 @@ func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int { return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } +// AscIfDefault is a sorting function to sort IfAddrs by whether or not they +// have a default route or not. Non-equal types are deferred in the sort. +// +// FIXME: This is a particularly expensive sorting operation because of the +// non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data +// once at the start of the sort and pass it along as a context or by wrapping +// the IfAddr type with this information (this would also solve the inability to +// return errors and the possibility of failing silently). Fortunately, +// N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth +// optimizing today. The common case is this gets called once or twice. +// Patches welcome. +func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int { + ri, err := NewRouteInfo() + if err != nil { + return sortDeferDecision + } + + defaultIfName, err := ri.GetDefaultInterfaceName() + if err != nil { + return sortDeferDecision + } + + switch { + case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName: + return sortDeferDecision + case p1Ptr.Interface.Name == defaultIfName: + return sortReceiverBeforeArg + case p2Ptr.Interface.Name == defaultIfName: + return sortArgBeforeReceiver + default: + return sortDeferDecision + } +} + // AscIfName is a sorting function to sort IfAddrs by their interface names. func AscIfName(p1Ptr, p2Ptr *IfAddr) int { return strings.Compare(p1Ptr.Name, p2Ptr.Name) @@ -127,6 +171,11 @@ func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } +// DescIfDefault is identical to AscIfDefault but reverse ordered. +func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int { + return -1 * AscIfDefault(p1Ptr, p2Ptr) +} + // DescIfName is identical to AscIfName but reverse ordered. func DescIfName(p1Ptr, p2Ptr *IfAddr) int { return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name) @@ -169,7 +218,15 @@ func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIf // IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is // more than one IfAddr, only the first IfAddr is used. -func IfAttr(selectorName string, ifAddrs IfAddrs) (string, error) { +func IfAttr(selectorName string, ifAddr IfAddr) (string, error) { + attrName := AttrName(strings.ToLower(selectorName)) + attrVal, err := ifAddr.Attr(attrName) + return attrVal, err +} + +// IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is +// more than one IfAddr, only the first IfAddr is used. +func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) { if len(ifAddrs) == 0 { return "", nil } @@ -243,10 +300,10 @@ func GetDefaultInterfaces() (IfAddrs, error) { // the `eval` equivalent of: // // ``` -// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | include "RFC" "6890" }}' +// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}' /// ``` func GetPrivateInterfaces() (IfAddrs, error) { - privateIfs, err := GetDefaultInterfaces() + privateIfs, err := GetAllInterfaces() if err != nil { return IfAddrs{}, err } @@ -259,15 +316,21 @@ func GetPrivateInterfaces() (IfAddrs, error) { return IfAddrs{}, nil } - privateIfs, _, err = IfByFlag("forwardable|up", privateIfs) + privateIfs, _, err = IfByFlag("forwardable", privateIfs) + if err != nil { + return IfAddrs{}, err + } + + privateIfs, _, err = IfByFlag("up", privateIfs) if err != nil { return IfAddrs{}, err } + if len(privateIfs) == 0 { return IfAddrs{}, nil } - OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(privateIfs) + OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs) privateIfs, _, err = IfByRFC("6890", privateIfs) if err != nil { @@ -285,10 +348,10 @@ func GetPrivateInterfaces() (IfAddrs, error) { // function is the `eval` equivalent of: // // ``` -// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | exclude "RFC" "6890" }}' +// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}' /// ``` func GetPublicInterfaces() (IfAddrs, error) { - publicIfs, err := GetDefaultInterfaces() + publicIfs, err := GetAllInterfaces() if err != nil { return IfAddrs{}, err } @@ -301,15 +364,21 @@ func GetPublicInterfaces() (IfAddrs, error) { return IfAddrs{}, nil } - publicIfs, _, err = IfByFlag("forwardable|up", publicIfs) + publicIfs, _, err = IfByFlag("forwardable", publicIfs) if err != nil { return IfAddrs{}, err } + + publicIfs, _, err = IfByFlag("up", publicIfs) + if err != nil { + return IfAddrs{}, err + } + if len(publicIfs) == 0 { return IfAddrs{}, nil } - OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(publicIfs) + OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs) _, publicIfs, err = IfByRFC("6890", publicIfs) if err != nil { @@ -652,6 +721,245 @@ func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, return includedIfs, excludedIfs, nil } +// IfAddrMath will return a new IfAddr struct with a mutated value. +func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) { + // Regexp used to enforce the sign being a required part of the grammar for + // some values. + signRe := signRE.Copy() + + switch strings.ToLower(operation) { + case "address": + // "address" operates on the IP address and is allowed to overflow or + // underflow networks, however it will wrap along the underlying address's + // underlying type. + + if !signRe.MatchString(value) { + return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) + } + + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + // 33 == Accept any uint32 value + // TODO(seanc@): Add the ability to parse hex + i, err := strconv.ParseInt(value, 10, 33) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + ipv4Uint32 := uint32(ipv4.Address) + ipv4Uint32 += uint32(i) + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: ipv4.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + // 64 == Accept any int32 value + // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. + i, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + ipv6BigIntA := new(big.Int) + ipv6BigIntA.Set(ipv6.Address) + ipv6BigIntB := big.NewInt(i) + + ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB) + ipv6Addr.And(ipv6Addr, ipv6HostMask) + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(ipv6Addr), + Mask: ipv6.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + case "network": + // "network" operates on the network address. Positive values start at the + // network address and negative values wrap at the network address, which + // means a "-1" value on a network will be the broadcast address after + // wrapping is applied. + + if !signRe.MatchString(value) { + return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) + } + + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + // 33 == Accept any uint32 value + // TODO(seanc@): Add the ability to parse hex + i, err := strconv.ParseInt(value, 10, 33) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + ipv4Uint32 := uint32(ipv4.NetworkAddress()) + + // Wrap along network mask boundaries. EZ-mode wrapping made possible by + // use of int64 vs a uint. + var wrappedMask int64 + if i >= 0 { + wrappedMask = i + } else { + wrappedMask = 1 + i + int64(^uint32(ipv4.Mask)) + } + + ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask)) + + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(ipv4Uint32), + Mask: ipv4.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + // 64 == Accept any int32 value + // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. + i, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + ipv6BigInt := new(big.Int) + ipv6BigInt.Set(ipv6.NetworkAddress()) + + mask := new(big.Int) + mask.Set(ipv6.Mask) + if i > 0 { + wrappedMask := new(big.Int) + wrappedMask.SetInt64(i) + + wrappedMask.AndNot(wrappedMask, mask) + ipv6BigInt.Add(ipv6BigInt, wrappedMask) + } else { + // Mask off any bits that exceed the network size. Subtract the + // wrappedMask from the last usable - 1 + wrappedMask := new(big.Int) + wrappedMask.SetInt64(-1 * i) + wrappedMask.Sub(wrappedMask, big.NewInt(1)) + + wrappedMask.AndNot(wrappedMask, mask) + + lastUsable := new(big.Int) + lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address) + + ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask) + } + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(ipv6BigInt), + Mask: ipv6.Mask, + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + case "mask": + // "mask" operates on the IP address and returns the IP address on + // which the given integer mask has been applied. If the applied mask + // corresponds to a larger network than the mask of the IP address, + // the latter will be replaced by the former. + switch sockType := inputIfAddr.SockAddr.Type(); sockType { + case TypeIPv4: + i, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + if i > 32 { + return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation) + } + + ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) + + ipv4Mask := net.CIDRMask(int(i), 32) + ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask) + + maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask) + maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4) + + maskedIpv4MaskUint32 := uint32(ipv4.Mask) + + if ipv4MaskUint32 < maskedIpv4MaskUint32 { + maskedIpv4MaskUint32 = ipv4MaskUint32 + } + + return IfAddr{ + SockAddr: IPv4Addr{ + Address: IPv4Address(maskedIpv4Uint32), + Mask: IPv4Mask(maskedIpv4MaskUint32), + }, + Interface: inputIfAddr.Interface, + }, nil + case TypeIPv6: + i, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) + } + + if i > 128 { + return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation) + } + + ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) + + ipv6Mask := net.CIDRMask(int(i), 128) + ipv6MaskBigInt := new(big.Int) + ipv6MaskBigInt.SetBytes(ipv6Mask) + + maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask) + maskedIpv6BigInt := new(big.Int) + maskedIpv6BigInt.SetBytes(maskedIpv6) + + maskedIpv6MaskBigInt := new(big.Int) + maskedIpv6MaskBigInt.Set(ipv6.Mask) + + if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 { + maskedIpv6MaskBigInt = ipv6MaskBigInt + } + + return IfAddr{ + SockAddr: IPv6Addr{ + Address: IPv6Address(maskedIpv6BigInt), + Mask: IPv6Mask(maskedIpv6MaskBigInt), + }, + Interface: inputIfAddr.Interface, + }, nil + default: + return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) + } + default: + return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation) + } +} + +// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any +// failure will result in zero results. +func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) { + outputAddrs := make(IfAddrs, 0, len(inputIfAddrs)) + for _, ifAddr := range inputIfAddrs { + result, err := IfAddrMath(operation, value, ifAddr) + if err != nil { + return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err) + } + outputAddrs = append(outputAddrs, result) + } + return outputAddrs, nil +} + // IncludeIfs returns an IfAddrs based on the passed in selector. func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { var includedIfs IfAddrs @@ -736,6 +1044,10 @@ func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { sortFuncs[i] = AscIfAddress case "-address": sortFuncs[i] = DescIfAddress + case "+default", "default": + sortFuncs[i] = AscIfDefault + case "-default": + sortFuncs[i] = DescIfDefault case "+name", "name": // The "name" selector returns an array of IfAddrs // ordered by the interface name. @@ -886,7 +1198,7 @@ func parseDefaultIfNameFromRoute(routeOut string) (string, error) { // Linux. func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") - re := regexp.MustCompile(`[\s]+`) + re := whitespaceRE.Copy() for _, line := range lines { kvs := re.Split(line, -1) if len(kvs) < 5 { @@ -929,7 +1241,7 @@ func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) { // support added. func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") - re := regexp.MustCompile(`[\s]+`) + re := whitespaceRE.Copy() for _, line := range lines { kvs := re.Split(strings.TrimSpace(line), -1) if len(kvs) < 3 { @@ -949,17 +1261,17 @@ func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) { // interface name forwarding traffic to the default gateway. func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") - ifNameRE := regexp.MustCompile(`^Ethernet adapter ([^\s:]+):`) - ipAddrRE := regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) + ifNameRe := ifNameRE.Copy() + ipAddrRe := ipAddrRE.Copy() var ifName string for _, line := range lines { - switch ifNameMatches := ifNameRE.FindStringSubmatch(line); { + switch ifNameMatches := ifNameRe.FindStringSubmatch(line); { case len(ifNameMatches) > 1: ifName = ifNameMatches[1] continue } - switch ipAddrMatches := ipAddrRE.FindStringSubmatch(line); { + switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); { case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr: return ifName, nil } diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go index 9f2616a69f627..4d395dc954b65 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go @@ -58,7 +58,8 @@ func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) { // Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In // particular, clients with the Barracuda VPN client will see something like: // `192.168.3.51/00ffffff` as their IP address. - if match := trailingHexNetmaskRE.FindStringIndex(ipv4Str); match != nil { + trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() + if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil { ipv4Str = ipv4Str[:match[0]] } diff --git a/vendor/github.com/hashicorp/go-sockaddr/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/rfc.go index fd9be940b1130..02e188f6fe647 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/rfc.go +++ b/vendor/github.com/hashicorp/go-sockaddr/rfc.go @@ -3,6 +3,7 @@ package sockaddr // ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP // blocks. const ForwardingBlacklist = 4294967295 +const ForwardingBlacklistRFC = "4294967295" // IsRFC tests to see if an SockAddr matches the specified RFC func IsRFC(rfcNum uint, sa SockAddr) bool { diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go index b33e4c0d0848e..c2ec91eaf456e 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go +++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go @@ -5,10 +5,6 @@ import ( "os/exec" ) -var cmds map[string][]string = map[string][]string{ - "ip": {"/sbin/ip", "route"}, -} - type routeInfo struct { cmds map[string][]string } @@ -16,15 +12,22 @@ type routeInfo struct { // NewRouteInfo returns a Linux-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { + // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on + // $PATH and fallback to /sbin/ip on error. + path, _ := exec.LookPath("ip") + if path == "" { + path = "/sbin/ip" + } + return routeInfo{ - cmds: cmds, + cmds: map[string][]string{"ip": {path, "route"}}, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { - out, err := exec.Command(cmds["ip"][0], cmds["ip"][1:]...).Output() + out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() if err != nil { return "", err } diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go index 51389ebe9a690..826c91c2e3d06 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go +++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go @@ -1,6 +1,7 @@ package sockaddr import ( + "encoding/json" "fmt" "strings" ) @@ -176,3 +177,30 @@ func sockAddrInit() { func SockAddrAttrs() []AttrName { return sockAddrAttrs } + +// Although this is pretty trivial to do in a program, having the logic here is +// useful all around. Note that this marshals into a *string* -- the underlying +// string representation of the sockaddr. If you then unmarshal into this type +// in Go, all will work as expected, but externally you can take what comes out +// and use the string value directly. +type SockAddrMarshaler struct { + SockAddr +} + +func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) { + return json.Marshal(s.SockAddr.String()) +} + +func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error { + var str string + err := json.Unmarshal(in, &str) + if err != nil { + return err + } + sa, err := NewSockAddr(str) + if err != nil { + return err + } + s.SockAddr = sa + return nil +} From cc1b68d5f2cf4f8dc77477632f10fc3b13a27908 Mon Sep 17 00:00:00 2001 From: Chris Telfer Date: Fri, 29 Jun 2018 15:15:52 -0400 Subject: [PATCH 2/2] Update tests w/ new libnetwork contraints The TestDockerNetworkIPAMMultipleNetworks test allocates several networks simultaneously with overlapping IP addresses. Libnetwork now forbids this. Adjust the test case to use distinct IP ranges for the networks it creates. Signed-off-by: Chris Telfer (cherry picked from commit efb7909befa0fe2236148543a6d50e2563bf386c) Signed-off-by: Sebastiaan van Stijn --- integration-cli/docker_cli_network_unix_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index 95f7ccfff07b8..a0abb6798a21c 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -610,17 +610,17 @@ func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *check.C) { // test network with multiple subnets // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports - dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6") + dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.170.0.0/16", "--subnet=192.171.0.0/16", "test6") assertNwIsAvailable(c, "test6") // test network with multiple subnets with valid ipam combinations // also check same subnet across networks when the driver supports it. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, - "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", - "--gateway=192.168.0.100", "--gateway=192.170.0.100", - "--ip-range=192.168.1.0/24", - "--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6", - "--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6", + "--subnet=192.172.0.0/16", "--subnet=192.173.0.0/16", + "--gateway=192.172.0.100", "--gateway=192.173.0.100", + "--ip-range=192.172.1.0/24", + "--aux-address", "a=192.172.1.5", "--aux-address", "b=192.172.1.6", + "--aux-address", "c=192.173.1.5", "--aux-address", "d=192.173.1.6", "test7") assertNwIsAvailable(c, "test7")