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 <ctelfer@docker.com>
| ... | ... |
@@ -3,7 +3,7 @@ |
| 3 | 3 |
# LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When |
| 4 | 4 |
# updating the binary version, consider updating github.com/docker/libnetwork |
| 5 | 5 |
# in vendor.conf accordingly |
| 6 |
-LIBNETWORK_COMMIT=19279f0492417475b6bfbd0aa529f73e8f178fb5 |
|
| 6 |
+LIBNETWORK_COMMIT=430c00a6a6b3dfdd774f21e1abd4ad6b0216c629 |
|
| 7 | 7 |
|
| 8 | 8 |
install_proxy() {
|
| 9 | 9 |
case "$1" in |
| ... | ... |
@@ -37,14 +37,14 @@ github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b |
| 37 | 37 |
#get libnetwork packages |
| 38 | 38 |
|
| 39 | 39 |
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly |
| 40 |
-github.com/docker/libnetwork 19279f0492417475b6bfbd0aa529f73e8f178fb5 |
|
| 40 |
+github.com/docker/libnetwork 430c00a6a6b3dfdd774f21e1abd4ad6b0216c629 |
|
| 41 | 41 |
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 |
| 42 | 42 |
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 43 | 43 |
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 44 | 44 |
github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b |
| 45 | 45 |
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c |
| 46 | 46 |
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 |
| 47 |
-github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d |
|
| 47 |
+github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9 |
|
| 48 | 48 |
github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e |
| 49 | 49 |
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 |
| 50 | 50 |
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef |
| ... | ... |
@@ -69,6 +69,7 @@ import ( |
| 69 | 69 |
"github.com/docker/libnetwork/netlabel" |
| 70 | 70 |
"github.com/docker/libnetwork/osl" |
| 71 | 71 |
"github.com/docker/libnetwork/types" |
| 72 |
+ "github.com/pkg/errors" |
|
| 72 | 73 |
"github.com/sirupsen/logrus" |
| 73 | 74 |
) |
| 74 | 75 |
|
| ... | ... |
@@ -1252,7 +1253,7 @@ func (c *controller) loadDriver(networkType string) error {
|
| 1252 | 1252 |
} |
| 1253 | 1253 |
|
| 1254 | 1254 |
if err != nil {
|
| 1255 |
- if err == plugins.ErrNotFound {
|
|
| 1255 |
+ if errors.Cause(err) == plugins.ErrNotFound {
|
|
| 1256 | 1256 |
return types.NotFoundErrorf(err.Error()) |
| 1257 | 1257 |
} |
| 1258 | 1258 |
return err |
| ... | ... |
@@ -29,7 +29,10 @@ const ( |
| 29 | 29 |
// Allocator provides per address space ipv4/ipv6 book keeping |
| 30 | 30 |
type Allocator struct {
|
| 31 | 31 |
// Predefined pools for default address spaces |
| 32 |
- predefined map[string][]*net.IPNet |
|
| 32 |
+ // Separate from the addrSpace because they should not be serialized |
|
| 33 |
+ predefined map[string][]*net.IPNet |
|
| 34 |
+ predefinedStartIndices map[string]int |
|
| 35 |
+ // The (potentially serialized) address spaces |
|
| 33 | 36 |
addrSpaces map[string]*addrSpace |
| 34 | 37 |
// stores []datastore.Datastore |
| 35 | 38 |
// Allocated addresses in each address space's subnet |
| ... | ... |
@@ -47,6 +50,9 @@ func NewAllocator(lcDs, glDs datastore.DataStore) (*Allocator, error) {
|
| 47 | 47 |
globalAddressSpace: ipamutils.PredefinedGranularNetworks, |
| 48 | 48 |
} |
| 49 | 49 |
|
| 50 |
+ // Initialize asIndices map |
|
| 51 |
+ a.predefinedStartIndices = make(map[string]int) |
|
| 52 |
+ |
|
| 50 | 53 |
// Initialize bitseq map |
| 51 | 54 |
a.addresses = make(map[SubnetKey]*bitseq.Handle) |
| 52 | 55 |
|
| ... | ... |
@@ -374,11 +380,24 @@ func (a *Allocator) retrieveBitmask(k SubnetKey, n *net.IPNet) (*bitseq.Handle, |
| 374 | 374 |
func (a *Allocator) getPredefineds(as string) []*net.IPNet {
|
| 375 | 375 |
a.Lock() |
| 376 | 376 |
defer a.Unlock() |
| 377 |
- l := make([]*net.IPNet, 0, len(a.predefined[as])) |
|
| 378 |
- for _, pool := range a.predefined[as] {
|
|
| 379 |
- l = append(l, pool) |
|
| 377 |
+ |
|
| 378 |
+ p := a.predefined[as] |
|
| 379 |
+ i := a.predefinedStartIndices[as] |
|
| 380 |
+ // defensive in case the list changed since last update |
|
| 381 |
+ if i >= len(p) {
|
|
| 382 |
+ i = 0 |
|
| 380 | 383 |
} |
| 381 |
- return l |
|
| 384 |
+ return append(p[i:], p[:i]...) |
|
| 385 |
+} |
|
| 386 |
+ |
|
| 387 |
+func (a *Allocator) updateStartIndex(as string, amt int) {
|
|
| 388 |
+ a.Lock() |
|
| 389 |
+ i := a.predefinedStartIndices[as] + amt |
|
| 390 |
+ if i < 0 || i >= len(a.predefined[as]) {
|
|
| 391 |
+ i = 0 |
|
| 392 |
+ } |
|
| 393 |
+ a.predefinedStartIndices[as] = i |
|
| 394 |
+ a.Unlock() |
|
| 382 | 395 |
} |
| 383 | 396 |
|
| 384 | 397 |
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) |
| 397 | 397 |
return nil, err |
| 398 | 398 |
} |
| 399 | 399 |
|
| 400 |
- for _, nw := range a.getPredefineds(as) {
|
|
| 400 |
+ predefined := a.getPredefineds(as) |
|
| 401 |
+ |
|
| 402 |
+ aSpace.Lock() |
|
| 403 |
+ for i, nw := range predefined {
|
|
| 401 | 404 |
if v != getAddressVersion(nw.IP) {
|
| 402 | 405 |
continue |
| 403 | 406 |
} |
| 404 |
- aSpace.Lock() |
|
| 407 |
+ // Checks whether pool has already been allocated |
|
| 405 | 408 |
if _, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]; ok {
|
| 406 |
- aSpace.Unlock() |
|
| 407 | 409 |
continue |
| 408 | 410 |
} |
| 411 |
+ // Shouldn't be necessary, but check prevents IP collisions should |
|
| 412 |
+ // predefined pools overlap for any reason. |
|
| 409 | 413 |
if !aSpace.contains(as, nw) {
|
| 410 | 414 |
aSpace.Unlock() |
| 415 |
+ a.updateStartIndex(as, i+1) |
|
| 411 | 416 |
return nw, nil |
| 412 | 417 |
} |
| 413 |
- aSpace.Unlock() |
|
| 414 | 418 |
} |
| 419 |
+ aSpace.Unlock() |
|
| 415 | 420 |
|
| 416 | 421 |
return nil, types.NotFoundErrorf("could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network", v)
|
| 417 | 422 |
} |
| ... | ... |
@@ -262,12 +262,13 @@ func (aSpace *addrSpace) updatePoolDBOnAdd(k SubnetKey, nw *net.IPNet, ipr *Addr |
| 262 | 262 |
defer aSpace.Unlock() |
| 263 | 263 |
|
| 264 | 264 |
// Check if already allocated |
| 265 |
- if p, ok := aSpace.subnets[k]; ok {
|
|
| 265 |
+ if _, ok := aSpace.subnets[k]; ok {
|
|
| 266 | 266 |
if pdf {
|
| 267 | 267 |
return nil, types.InternalMaskableErrorf("predefined pool %s is already reserved", nw)
|
| 268 | 268 |
} |
| 269 |
- aSpace.incRefCount(p, 1) |
|
| 270 |
- return func() error { return nil }, nil
|
|
| 269 |
+ // This means the same pool is already allocated. updatePoolDBOnAdd is called when there |
|
| 270 |
+ // is request for a pool/subpool. It should ensure there is no overlap with existing pools |
|
| 271 |
+ return nil, ipamapi.ErrPoolOverlap |
|
| 271 | 272 |
} |
| 272 | 273 |
|
| 273 | 274 |
// If master pool, check for overlap |
| ... | ... |
@@ -1156,26 +1156,27 @@ func (n *network) createEndpoint(name string, options ...EndpointOption) (Endpoi |
| 1156 | 1156 |
ep.releaseAddress() |
| 1157 | 1157 |
} |
| 1158 | 1158 |
}() |
| 1159 |
- // Moving updateToSTore before calling addEndpoint so that we shall clean up VETH interfaces in case |
|
| 1160 |
- // DockerD get killed between addEndpoint and updateSTore call |
|
| 1161 |
- if err = n.getController().updateToStore(ep); err != nil {
|
|
| 1159 |
+ |
|
| 1160 |
+ if err = n.addEndpoint(ep); err != nil {
|
|
| 1162 | 1161 |
return nil, err |
| 1163 | 1162 |
} |
| 1164 | 1163 |
defer func() {
|
| 1165 | 1164 |
if err != nil {
|
| 1166 |
- if e := n.getController().deleteFromStore(ep); e != nil {
|
|
| 1167 |
- logrus.Warnf("error rolling back endpoint %s from store: %v", name, e)
|
|
| 1165 |
+ if e := ep.deleteEndpoint(false); e != nil {
|
|
| 1166 |
+ logrus.Warnf("cleaning up endpoint failed %s : %v", name, e)
|
|
| 1168 | 1167 |
} |
| 1169 | 1168 |
} |
| 1170 | 1169 |
}() |
| 1171 | 1170 |
|
| 1172 |
- if err = n.addEndpoint(ep); err != nil {
|
|
| 1171 |
+ // We should perform updateToStore call right after addEndpoint |
|
| 1172 |
+ // in order to have iface properly configured |
|
| 1173 |
+ if err = n.getController().updateToStore(ep); err != nil {
|
|
| 1173 | 1174 |
return nil, err |
| 1174 | 1175 |
} |
| 1175 | 1176 |
defer func() {
|
| 1176 | 1177 |
if err != nil {
|
| 1177 |
- if e := ep.deleteEndpoint(false); e != nil {
|
|
| 1178 |
- logrus.Warnf("cleaning up endpoint failed %s : %v", name, e)
|
|
| 1178 |
+ if e := n.getController().deleteFromStore(ep); e != nil {
|
|
| 1179 |
+ logrus.Warnf("error rolling back endpoint %s from store: %v", name, e)
|
|
| 1179 | 1180 |
} |
| 1180 | 1181 |
} |
| 1181 | 1182 |
}() |
| ... | ... |
@@ -41,7 +41,7 @@ func (nDB *NetworkDB) handleNodeEvent(nEvent *NodeEvent) bool {
|
| 41 | 41 |
// If the node is not known from memberlist we cannot process save any state of it else if it actually |
| 42 | 42 |
// dies we won't receive any notification and we will remain stuck with it |
| 43 | 43 |
if _, ok := nDB.nodes[nEvent.NodeName]; !ok {
|
| 44 |
- logrus.Error("node: %s is unknown to memberlist", nEvent.NodeName)
|
|
| 44 |
+ logrus.Errorf("node: %s is unknown to memberlist", nEvent.NodeName)
|
|
| 45 | 45 |
return false |
| 46 | 46 |
} |
| 47 | 47 |
|
| ... | ... |
@@ -145,7 +145,12 @@ func (p *PortBinding) String() string {
|
| 145 | 145 |
return ret |
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 |
-// FromString reads the PortBinding structure from string |
|
| 148 |
+// FromString reads the PortBinding structure from string s. |
|
| 149 |
+// String s is a triple of "protocol/containerIP:port/hostIP:port" |
|
| 150 |
+// containerIP and hostIP can be in dotted decimal ("192.0.2.1") or IPv6 ("2001:db8::68") form.
|
|
| 151 |
+// Zoned addresses ("169.254.0.23%eth0" or "fe80::1ff:fe23:4567:890a%eth0") are not supported.
|
|
| 152 |
+// If string s is incorrectly formatted or the IP addresses or ports cannot be parsed, FromString |
|
| 153 |
+// returns an error. |
|
| 149 | 154 |
func (p *PortBinding) FromString(s string) error {
|
| 150 | 155 |
ps := strings.Split(s, "/") |
| 151 | 156 |
if len(ps) != 3 {
|
| ... | ... |
@@ -167,21 +172,19 @@ func (p *PortBinding) FromString(s string) error {
|
| 167 | 167 |
} |
| 168 | 168 |
|
| 169 | 169 |
func parseIPPort(s string) (net.IP, uint16, error) {
|
| 170 |
- pp := strings.Split(s, ":") |
|
| 171 |
- if len(pp) != 2 {
|
|
| 172 |
- return nil, 0, BadRequestErrorf("invalid format: %s", s)
|
|
| 170 |
+ hoststr, portstr, err := net.SplitHostPort(s) |
|
| 171 |
+ if err != nil {
|
|
| 172 |
+ return nil, 0, err |
|
| 173 | 173 |
} |
| 174 | 174 |
|
| 175 |
- var ip net.IP |
|
| 176 |
- if pp[0] != "" {
|
|
| 177 |
- if ip = net.ParseIP(pp[0]); ip == nil {
|
|
| 178 |
- return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
|
|
| 179 |
- } |
|
| 175 |
+ ip := net.ParseIP(hoststr) |
|
| 176 |
+ if ip == nil {
|
|
| 177 |
+ return nil, 0, BadRequestErrorf("invalid ip: %s", hoststr)
|
|
| 180 | 178 |
} |
| 181 | 179 |
|
| 182 |
- port, err := strconv.ParseUint(pp[1], 10, 16) |
|
| 180 |
+ port, err := strconv.ParseUint(portstr, 10, 16) |
|
| 183 | 181 |
if err != nil {
|
| 184 |
- return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
|
|
| 182 |
+ return nil, 0, BadRequestErrorf("invalid port: %s", portstr)
|
|
| 185 | 183 |
} |
| 186 | 184 |
|
| 187 | 185 |
return ip, uint16(port), nil |
| ... | ... |
@@ -1,27 +1,28 @@ |
| 1 | 1 |
github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 |
| 2 | 2 |
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 |
| 3 |
-github.com/Microsoft/go-winio v0.4.5 |
|
| 4 |
-github.com/Microsoft/hcsshim v0.6.5 |
|
| 3 |
+github.com/Microsoft/go-winio v0.4.7 |
|
| 4 |
+github.com/Microsoft/hcsshim v0.6.11 |
|
| 5 | 5 |
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| 6 | 6 |
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 7 | 7 |
github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 |
| 8 | 8 |
github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904 |
| 9 |
-github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e |
|
| 10 |
-github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8 |
|
| 9 |
+github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925 |
|
| 10 |
+github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b |
|
| 11 | 11 |
github.com/coreos/etcd v3.2.1 |
| 12 | 12 |
github.com/coreos/go-semver v0.2.0 |
| 13 |
-github.com/coreos/go-systemd v4 |
|
| 13 |
+github.com/coreos/go-systemd v17 |
|
| 14 |
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 |
|
| 14 | 15 |
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d |
| 15 | 16 |
|
| 16 |
-github.com/docker/docker a3efe9722f34af5cf4443fe3a5c4e4e3e0457b54 |
|
| 17 |
-github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d |
|
| 17 |
+github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149 |
|
| 18 |
+github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6 |
|
| 18 | 19 |
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 |
| 19 | 20 |
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 |
| 20 | 21 |
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef |
| 21 | 22 |
|
| 22 | 23 |
github.com/godbus/dbus v4.0.0 |
| 23 |
-github.com/gogo/protobuf v0.4 |
|
| 24 |
-github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 |
|
| 24 |
+github.com/gogo/protobuf v1.0.0 |
|
| 25 |
+github.com/golang/protobuf v1.1.0 |
|
| 25 | 26 |
github.com/gorilla/context v1.1 |
| 26 | 27 |
github.com/gorilla/mux v1.1 |
| 27 | 28 |
github.com/hashicorp/consul v0.5.2 |
| ... | ... |
@@ -29,27 +30,37 @@ github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b |
| 29 | 29 |
github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e |
| 30 | 30 |
github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c |
| 31 | 31 |
github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 |
| 32 |
-github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d |
|
| 32 |
+github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9 |
|
| 33 | 33 |
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 |
| 34 | 34 |
github.com/mattn/go-shellwords v1.0.3 |
| 35 |
-github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7 |
|
| 35 |
+github.com/miekg/dns v1.0.7 |
|
| 36 | 36 |
github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08 |
| 37 |
-github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb |
|
| 38 |
-github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13 |
|
| 39 |
-github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d |
|
| 40 |
-github.com/opencontainers/runtime-spec v1.0.0 |
|
| 41 |
-github.com/opencontainers/selinux v1.0.0-rc1 |
|
| 37 |
+github.com/opencontainers/go-digest v1.0.0-rc1 |
|
| 38 |
+github.com/opencontainers/image-spec v1.0.1 |
|
| 39 |
+github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340 |
|
| 40 |
+github.com/opencontainers/runtime-spec v1.0.1 |
|
| 41 |
+github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd |
|
| 42 | 42 |
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 |
| 43 | 43 |
github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 |
| 44 | 44 |
github.com/sirupsen/logrus v1.0.3 |
| 45 | 45 |
github.com/stretchr/testify dab07ac62d4905d3e48d17dc549c684ac3b7c15a |
| 46 |
-github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16 |
|
| 46 |
+github.com/syndtr/gocapability 33e07d32887e1e06b7c025f27ce52f62c7990bc0 |
|
| 47 | 47 |
github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065 |
| 48 | 48 |
github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e |
| 49 | 49 |
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 |
| 50 |
-golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca |
|
| 51 |
-golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac |
|
| 52 |
-golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5 |
|
| 50 |
+golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491 |
|
| 51 |
+golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd |
|
| 52 |
+golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd |
|
| 53 | 53 |
golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5 |
| 54 | 54 |
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 |
| 55 | 55 |
github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb |
| 56 |
+ |
|
| 57 |
+github.com/davecgh/go-spew 8991bc29aa16c548c550c7ff78260e27b9ab7c73 |
|
| 58 |
+github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2 |
|
| 59 |
+github.com/cyphar/filepath-securejoin v0.2.1 |
|
| 60 |
+github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55 |
|
| 61 |
+github.com/hashicorp/go-immutable-radix 7f3cd4390caab3250a57f30efdb2a65dd7649ecf |
|
| 62 |
+github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3 |
|
| 63 |
+github.com/hashicorp/go-cleanhttp d5fe4b57a186c716b0e00b8c301cbd9b4182694d |
|
| 64 |
+github.com/hashicorp/go-rootcerts 6bb64b370b90e7ef1fa532be9e591a81c3493e00 |
|
| 65 |
+github.com/mitchellh/go-homedir 3864e76763d94a6df2f9960b16a20a33da9f9a66 |
| ... | ... |
@@ -1,5 +1,7 @@ |
| 1 | 1 |
package sockaddr |
| 2 | 2 |
|
| 3 |
+import "strings" |
|
| 4 |
+ |
|
| 3 | 5 |
// ifAddrAttrMap is a map of the IfAddr type-specific attributes. |
| 4 | 6 |
var ifAddrAttrMap map[AttrName]func(IfAddr) string |
| 5 | 7 |
var ifAddrAttrs []AttrName |
| ... | ... |
@@ -30,6 +32,53 @@ func GetPrivateIP() (string, error) {
|
| 30 | 30 |
return ip.NetIP().String(), nil |
| 31 | 31 |
} |
| 32 | 32 |
|
| 33 |
+// GetPrivateIPs returns a string with all IP addresses that are part of RFC |
|
| 34 |
+// 6890 (regardless of whether or not there is a default route, unlike |
|
| 35 |
+// GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty |
|
| 36 |
+// string will be returned instead. This function is the `eval` equivalent of: |
|
| 37 |
+// |
|
| 38 |
+// ``` |
|
| 39 |
+// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}'
|
|
| 40 |
+/// ``` |
|
| 41 |
+func GetPrivateIPs() (string, error) {
|
|
| 42 |
+ ifAddrs, err := GetAllInterfaces() |
|
| 43 |
+ if err != nil {
|
|
| 44 |
+ return "", err |
|
| 45 |
+ } else if len(ifAddrs) < 1 {
|
|
| 46 |
+ return "", nil |
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) |
|
| 50 |
+ if len(ifAddrs) == 0 {
|
|
| 51 |
+ return "", nil |
|
| 52 |
+ } |
|
| 53 |
+ |
|
| 54 |
+ OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) |
|
| 55 |
+ |
|
| 56 |
+ ifAddrs, _, err = IfByRFC("6890", ifAddrs)
|
|
| 57 |
+ if err != nil {
|
|
| 58 |
+ return "", err |
|
| 59 |
+ } else if len(ifAddrs) == 0 {
|
|
| 60 |
+ return "", nil |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs) |
|
| 64 |
+ if err != nil {
|
|
| 65 |
+ return "", err |
|
| 66 |
+ } else if len(ifAddrs) == 0 {
|
|
| 67 |
+ return "", nil |
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ ips := make([]string, 0, len(ifAddrs)) |
|
| 71 |
+ for _, ifAddr := range ifAddrs {
|
|
| 72 |
+ ip := *ToIPAddr(ifAddr.SockAddr) |
|
| 73 |
+ s := ip.NetIP().String() |
|
| 74 |
+ ips = append(ips, s) |
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 77 |
+ return strings.Join(ips, " "), nil |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 33 | 80 |
// GetPublicIP returns a string with a single IP address that is NOT part of RFC |
| 34 | 81 |
// 6890 and has a default route. If the system can't determine its IP address |
| 35 | 82 |
// or find a non RFC 6890 IP address, an empty string will be returned instead. |
| ... | ... |
@@ -51,6 +100,47 @@ func GetPublicIP() (string, error) {
|
| 51 | 51 |
return ip.NetIP().String(), nil |
| 52 | 52 |
} |
| 53 | 53 |
|
| 54 |
+// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC |
|
| 55 |
+// 6890 (regardless of whether or not there is a default route, unlike |
|
| 56 |
+// GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an |
|
| 57 |
+// empty string will be returned instead. This function is the `eval` |
|
| 58 |
+// equivalent of: |
|
| 59 |
+// |
|
| 60 |
+// ``` |
|
| 61 |
+// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}'
|
|
| 62 |
+/// ``` |
|
| 63 |
+func GetPublicIPs() (string, error) {
|
|
| 64 |
+ ifAddrs, err := GetAllInterfaces() |
|
| 65 |
+ if err != nil {
|
|
| 66 |
+ return "", err |
|
| 67 |
+ } else if len(ifAddrs) < 1 {
|
|
| 68 |
+ return "", nil |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) |
|
| 72 |
+ if len(ifAddrs) == 0 {
|
|
| 73 |
+ return "", nil |
|
| 74 |
+ } |
|
| 75 |
+ |
|
| 76 |
+ OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) |
|
| 77 |
+ |
|
| 78 |
+ _, ifAddrs, err = IfByRFC("6890", ifAddrs)
|
|
| 79 |
+ if err != nil {
|
|
| 80 |
+ return "", err |
|
| 81 |
+ } else if len(ifAddrs) == 0 {
|
|
| 82 |
+ return "", nil |
|
| 83 |
+ } |
|
| 84 |
+ |
|
| 85 |
+ ips := make([]string, 0, len(ifAddrs)) |
|
| 86 |
+ for _, ifAddr := range ifAddrs {
|
|
| 87 |
+ ip := *ToIPAddr(ifAddr.SockAddr) |
|
| 88 |
+ s := ip.NetIP().String() |
|
| 89 |
+ ips = append(ips, s) |
|
| 90 |
+ } |
|
| 91 |
+ |
|
| 92 |
+ return strings.Join(ips, " "), nil |
|
| 93 |
+} |
|
| 94 |
+ |
|
| 54 | 95 |
// GetInterfaceIP returns a string with a single IP address sorted by the size |
| 55 | 96 |
// of the network (i.e. IP addresses with a smaller netmask, larger network |
| 56 | 97 |
// size, are sorted first). This function is the `eval` equivalent of: |
| ... | ... |
@@ -91,6 +181,44 @@ func GetInterfaceIP(namedIfRE string) (string, error) {
|
| 91 | 91 |
return IPAddrAttr(*ip, "address"), nil |
| 92 | 92 |
} |
| 93 | 93 |
|
| 94 |
+// GetInterfaceIPs returns a string with all IPs, sorted by the size of the |
|
| 95 |
+// network (i.e. IP addresses with a smaller netmask, larger network size, are |
|
| 96 |
+// sorted first), on a named interface. This function is the `eval` equivalent |
|
| 97 |
+// of: |
|
| 98 |
+// |
|
| 99 |
+// ``` |
|
| 100 |
+// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | join "address" " "}}'
|
|
| 101 |
+/// ``` |
|
| 102 |
+func GetInterfaceIPs(namedIfRE string) (string, error) {
|
|
| 103 |
+ ifAddrs, err := GetAllInterfaces() |
|
| 104 |
+ if err != nil {
|
|
| 105 |
+ return "", err |
|
| 106 |
+ } |
|
| 107 |
+ |
|
| 108 |
+ ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) |
|
| 109 |
+ if err != nil {
|
|
| 110 |
+ return "", err |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
|
|
| 114 |
+ if err != nil {
|
|
| 115 |
+ return "", err |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ if len(ifAddrs) == 0 {
|
|
| 119 |
+ return "", err |
|
| 120 |
+ } |
|
| 121 |
+ |
|
| 122 |
+ ips := make([]string, 0, len(ifAddrs)) |
|
| 123 |
+ for _, ifAddr := range ifAddrs {
|
|
| 124 |
+ ip := *ToIPAddr(ifAddr.SockAddr) |
|
| 125 |
+ s := ip.NetIP().String() |
|
| 126 |
+ ips = append(ips, s) |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ return strings.Join(ips, " "), nil |
|
| 130 |
+} |
|
| 131 |
+ |
|
| 94 | 132 |
// IfAddrAttrs returns a list of attributes supported by the IfAddr type |
| 95 | 133 |
func IfAddrAttrs() []AttrName {
|
| 96 | 134 |
return ifAddrAttrs |
| ... | ... |
@@ -1,8 +1,10 @@ |
| 1 | 1 |
package sockaddr |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/binary" |
|
| 4 | 5 |
"errors" |
| 5 | 6 |
"fmt" |
| 7 |
+ "math/big" |
|
| 6 | 8 |
"net" |
| 7 | 9 |
"regexp" |
| 8 | 10 |
"sort" |
| ... | ... |
@@ -10,6 +12,14 @@ import ( |
| 10 | 10 |
"strings" |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 |
+var ( |
|
| 14 |
+ // Centralize all regexps and regexp.Copy() where necessary. |
|
| 15 |
+ signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`) |
|
| 16 |
+ whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`) |
|
| 17 |
+ ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`) |
|
| 18 |
+ ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) |
|
| 19 |
+) |
|
| 20 |
+ |
|
| 13 | 21 |
// IfAddrs is a slice of IfAddr |
| 14 | 22 |
type IfAddrs []IfAddr |
| 15 | 23 |
|
| ... | ... |
@@ -91,6 +101,40 @@ func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int {
|
| 91 | 91 |
return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
| 92 | 92 |
} |
| 93 | 93 |
|
| 94 |
+// AscIfDefault is a sorting function to sort IfAddrs by whether or not they |
|
| 95 |
+// have a default route or not. Non-equal types are deferred in the sort. |
|
| 96 |
+// |
|
| 97 |
+// FIXME: This is a particularly expensive sorting operation because of the |
|
| 98 |
+// non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data |
|
| 99 |
+// once at the start of the sort and pass it along as a context or by wrapping |
|
| 100 |
+// the IfAddr type with this information (this would also solve the inability to |
|
| 101 |
+// return errors and the possibility of failing silently). Fortunately, |
|
| 102 |
+// N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth |
|
| 103 |
+// optimizing today. The common case is this gets called once or twice. |
|
| 104 |
+// Patches welcome. |
|
| 105 |
+func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int {
|
|
| 106 |
+ ri, err := NewRouteInfo() |
|
| 107 |
+ if err != nil {
|
|
| 108 |
+ return sortDeferDecision |
|
| 109 |
+ } |
|
| 110 |
+ |
|
| 111 |
+ defaultIfName, err := ri.GetDefaultInterfaceName() |
|
| 112 |
+ if err != nil {
|
|
| 113 |
+ return sortDeferDecision |
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ switch {
|
|
| 117 |
+ case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName: |
|
| 118 |
+ return sortDeferDecision |
|
| 119 |
+ case p1Ptr.Interface.Name == defaultIfName: |
|
| 120 |
+ return sortReceiverBeforeArg |
|
| 121 |
+ case p2Ptr.Interface.Name == defaultIfName: |
|
| 122 |
+ return sortArgBeforeReceiver |
|
| 123 |
+ default: |
|
| 124 |
+ return sortDeferDecision |
|
| 125 |
+ } |
|
| 126 |
+} |
|
| 127 |
+ |
|
| 94 | 128 |
// AscIfName is a sorting function to sort IfAddrs by their interface names. |
| 95 | 129 |
func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
|
| 96 | 130 |
return strings.Compare(p1Ptr.Name, p2Ptr.Name) |
| ... | ... |
@@ -127,6 +171,11 @@ func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int {
|
| 127 | 127 |
return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) |
| 128 | 128 |
} |
| 129 | 129 |
|
| 130 |
+// DescIfDefault is identical to AscIfDefault but reverse ordered. |
|
| 131 |
+func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int {
|
|
| 132 |
+ return -1 * AscIfDefault(p1Ptr, p2Ptr) |
|
| 133 |
+} |
|
| 134 |
+ |
|
| 130 | 135 |
// DescIfName is identical to AscIfName but reverse ordered. |
| 131 | 136 |
func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
|
| 132 | 137 |
return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name) |
| ... | ... |
@@ -169,7 +218,15 @@ func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIf |
| 169 | 169 |
|
| 170 | 170 |
// IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is |
| 171 | 171 |
// more than one IfAddr, only the first IfAddr is used. |
| 172 |
-func IfAttr(selectorName string, ifAddrs IfAddrs) (string, error) {
|
|
| 172 |
+func IfAttr(selectorName string, ifAddr IfAddr) (string, error) {
|
|
| 173 |
+ attrName := AttrName(strings.ToLower(selectorName)) |
|
| 174 |
+ attrVal, err := ifAddr.Attr(attrName) |
|
| 175 |
+ return attrVal, err |
|
| 176 |
+} |
|
| 177 |
+ |
|
| 178 |
+// IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is |
|
| 179 |
+// more than one IfAddr, only the first IfAddr is used. |
|
| 180 |
+func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) {
|
|
| 173 | 181 |
if len(ifAddrs) == 0 {
|
| 174 | 182 |
return "", nil |
| 175 | 183 |
} |
| ... | ... |
@@ -243,10 +300,10 @@ func GetDefaultInterfaces() (IfAddrs, error) {
|
| 243 | 243 |
// the `eval` equivalent of: |
| 244 | 244 |
// |
| 245 | 245 |
// ``` |
| 246 |
-// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | include "RFC" "6890" }}'
|
|
| 246 |
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}'
|
|
| 247 | 247 |
/// ``` |
| 248 | 248 |
func GetPrivateInterfaces() (IfAddrs, error) {
|
| 249 |
- privateIfs, err := GetDefaultInterfaces() |
|
| 249 |
+ privateIfs, err := GetAllInterfaces() |
|
| 250 | 250 |
if err != nil {
|
| 251 | 251 |
return IfAddrs{}, err
|
| 252 | 252 |
} |
| ... | ... |
@@ -259,15 +316,21 @@ func GetPrivateInterfaces() (IfAddrs, error) {
|
| 259 | 259 |
return IfAddrs{}, nil
|
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 |
- privateIfs, _, err = IfByFlag("forwardable|up", privateIfs)
|
|
| 262 |
+ privateIfs, _, err = IfByFlag("forwardable", privateIfs)
|
|
| 263 |
+ if err != nil {
|
|
| 264 |
+ return IfAddrs{}, err
|
|
| 265 |
+ } |
|
| 266 |
+ |
|
| 267 |
+ privateIfs, _, err = IfByFlag("up", privateIfs)
|
|
| 263 | 268 |
if err != nil {
|
| 264 | 269 |
return IfAddrs{}, err
|
| 265 | 270 |
} |
| 271 |
+ |
|
| 266 | 272 |
if len(privateIfs) == 0 {
|
| 267 | 273 |
return IfAddrs{}, nil
|
| 268 | 274 |
} |
| 269 | 275 |
|
| 270 |
- OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(privateIfs) |
|
| 276 |
+ OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs) |
|
| 271 | 277 |
|
| 272 | 278 |
privateIfs, _, err = IfByRFC("6890", privateIfs)
|
| 273 | 279 |
if err != nil {
|
| ... | ... |
@@ -285,10 +348,10 @@ func GetPrivateInterfaces() (IfAddrs, error) {
|
| 285 | 285 |
// function is the `eval` equivalent of: |
| 286 | 286 |
// |
| 287 | 287 |
// ``` |
| 288 |
-// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | exclude "RFC" "6890" }}'
|
|
| 288 |
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}'
|
|
| 289 | 289 |
/// ``` |
| 290 | 290 |
func GetPublicInterfaces() (IfAddrs, error) {
|
| 291 |
- publicIfs, err := GetDefaultInterfaces() |
|
| 291 |
+ publicIfs, err := GetAllInterfaces() |
|
| 292 | 292 |
if err != nil {
|
| 293 | 293 |
return IfAddrs{}, err
|
| 294 | 294 |
} |
| ... | ... |
@@ -301,15 +364,21 @@ func GetPublicInterfaces() (IfAddrs, error) {
|
| 301 | 301 |
return IfAddrs{}, nil
|
| 302 | 302 |
} |
| 303 | 303 |
|
| 304 |
- publicIfs, _, err = IfByFlag("forwardable|up", publicIfs)
|
|
| 304 |
+ publicIfs, _, err = IfByFlag("forwardable", publicIfs)
|
|
| 305 | 305 |
if err != nil {
|
| 306 | 306 |
return IfAddrs{}, err
|
| 307 | 307 |
} |
| 308 |
+ |
|
| 309 |
+ publicIfs, _, err = IfByFlag("up", publicIfs)
|
|
| 310 |
+ if err != nil {
|
|
| 311 |
+ return IfAddrs{}, err
|
|
| 312 |
+ } |
|
| 313 |
+ |
|
| 308 | 314 |
if len(publicIfs) == 0 {
|
| 309 | 315 |
return IfAddrs{}, nil
|
| 310 | 316 |
} |
| 311 | 317 |
|
| 312 |
- OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(publicIfs) |
|
| 318 |
+ OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs) |
|
| 313 | 319 |
|
| 314 | 320 |
_, publicIfs, err = IfByRFC("6890", publicIfs)
|
| 315 | 321 |
if err != nil {
|
| ... | ... |
@@ -652,6 +721,245 @@ func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, |
| 652 | 652 |
return includedIfs, excludedIfs, nil |
| 653 | 653 |
} |
| 654 | 654 |
|
| 655 |
+// IfAddrMath will return a new IfAddr struct with a mutated value. |
|
| 656 |
+func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
|
|
| 657 |
+ // Regexp used to enforce the sign being a required part of the grammar for |
|
| 658 |
+ // some values. |
|
| 659 |
+ signRe := signRE.Copy() |
|
| 660 |
+ |
|
| 661 |
+ switch strings.ToLower(operation) {
|
|
| 662 |
+ case "address": |
|
| 663 |
+ // "address" operates on the IP address and is allowed to overflow or |
|
| 664 |
+ // underflow networks, however it will wrap along the underlying address's |
|
| 665 |
+ // underlying type. |
|
| 666 |
+ |
|
| 667 |
+ if !signRe.MatchString(value) {
|
|
| 668 |
+ return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
|
|
| 669 |
+ } |
|
| 670 |
+ |
|
| 671 |
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
|
|
| 672 |
+ case TypeIPv4: |
|
| 673 |
+ // 33 == Accept any uint32 value |
|
| 674 |
+ // TODO(seanc@): Add the ability to parse hex |
|
| 675 |
+ i, err := strconv.ParseInt(value, 10, 33) |
|
| 676 |
+ if err != nil {
|
|
| 677 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 678 |
+ } |
|
| 679 |
+ |
|
| 680 |
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) |
|
| 681 |
+ ipv4Uint32 := uint32(ipv4.Address) |
|
| 682 |
+ ipv4Uint32 += uint32(i) |
|
| 683 |
+ return IfAddr{
|
|
| 684 |
+ SockAddr: IPv4Addr{
|
|
| 685 |
+ Address: IPv4Address(ipv4Uint32), |
|
| 686 |
+ Mask: ipv4.Mask, |
|
| 687 |
+ }, |
|
| 688 |
+ Interface: inputIfAddr.Interface, |
|
| 689 |
+ }, nil |
|
| 690 |
+ case TypeIPv6: |
|
| 691 |
+ // 64 == Accept any int32 value |
|
| 692 |
+ // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. |
|
| 693 |
+ i, err := strconv.ParseInt(value, 10, 64) |
|
| 694 |
+ if err != nil {
|
|
| 695 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 696 |
+ } |
|
| 697 |
+ |
|
| 698 |
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) |
|
| 699 |
+ ipv6BigIntA := new(big.Int) |
|
| 700 |
+ ipv6BigIntA.Set(ipv6.Address) |
|
| 701 |
+ ipv6BigIntB := big.NewInt(i) |
|
| 702 |
+ |
|
| 703 |
+ ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB) |
|
| 704 |
+ ipv6Addr.And(ipv6Addr, ipv6HostMask) |
|
| 705 |
+ |
|
| 706 |
+ return IfAddr{
|
|
| 707 |
+ SockAddr: IPv6Addr{
|
|
| 708 |
+ Address: IPv6Address(ipv6Addr), |
|
| 709 |
+ Mask: ipv6.Mask, |
|
| 710 |
+ }, |
|
| 711 |
+ Interface: inputIfAddr.Interface, |
|
| 712 |
+ }, nil |
|
| 713 |
+ default: |
|
| 714 |
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
|
| 715 |
+ } |
|
| 716 |
+ case "network": |
|
| 717 |
+ // "network" operates on the network address. Positive values start at the |
|
| 718 |
+ // network address and negative values wrap at the network address, which |
|
| 719 |
+ // means a "-1" value on a network will be the broadcast address after |
|
| 720 |
+ // wrapping is applied. |
|
| 721 |
+ |
|
| 722 |
+ if !signRe.MatchString(value) {
|
|
| 723 |
+ return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
|
|
| 724 |
+ } |
|
| 725 |
+ |
|
| 726 |
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
|
|
| 727 |
+ case TypeIPv4: |
|
| 728 |
+ // 33 == Accept any uint32 value |
|
| 729 |
+ // TODO(seanc@): Add the ability to parse hex |
|
| 730 |
+ i, err := strconv.ParseInt(value, 10, 33) |
|
| 731 |
+ if err != nil {
|
|
| 732 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 733 |
+ } |
|
| 734 |
+ |
|
| 735 |
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) |
|
| 736 |
+ ipv4Uint32 := uint32(ipv4.NetworkAddress()) |
|
| 737 |
+ |
|
| 738 |
+ // Wrap along network mask boundaries. EZ-mode wrapping made possible by |
|
| 739 |
+ // use of int64 vs a uint. |
|
| 740 |
+ var wrappedMask int64 |
|
| 741 |
+ if i >= 0 {
|
|
| 742 |
+ wrappedMask = i |
|
| 743 |
+ } else {
|
|
| 744 |
+ wrappedMask = 1 + i + int64(^uint32(ipv4.Mask)) |
|
| 745 |
+ } |
|
| 746 |
+ |
|
| 747 |
+ ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask)) |
|
| 748 |
+ |
|
| 749 |
+ return IfAddr{
|
|
| 750 |
+ SockAddr: IPv4Addr{
|
|
| 751 |
+ Address: IPv4Address(ipv4Uint32), |
|
| 752 |
+ Mask: ipv4.Mask, |
|
| 753 |
+ }, |
|
| 754 |
+ Interface: inputIfAddr.Interface, |
|
| 755 |
+ }, nil |
|
| 756 |
+ case TypeIPv6: |
|
| 757 |
+ // 64 == Accept any int32 value |
|
| 758 |
+ // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. |
|
| 759 |
+ i, err := strconv.ParseInt(value, 10, 64) |
|
| 760 |
+ if err != nil {
|
|
| 761 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 762 |
+ } |
|
| 763 |
+ |
|
| 764 |
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) |
|
| 765 |
+ ipv6BigInt := new(big.Int) |
|
| 766 |
+ ipv6BigInt.Set(ipv6.NetworkAddress()) |
|
| 767 |
+ |
|
| 768 |
+ mask := new(big.Int) |
|
| 769 |
+ mask.Set(ipv6.Mask) |
|
| 770 |
+ if i > 0 {
|
|
| 771 |
+ wrappedMask := new(big.Int) |
|
| 772 |
+ wrappedMask.SetInt64(i) |
|
| 773 |
+ |
|
| 774 |
+ wrappedMask.AndNot(wrappedMask, mask) |
|
| 775 |
+ ipv6BigInt.Add(ipv6BigInt, wrappedMask) |
|
| 776 |
+ } else {
|
|
| 777 |
+ // Mask off any bits that exceed the network size. Subtract the |
|
| 778 |
+ // wrappedMask from the last usable - 1 |
|
| 779 |
+ wrappedMask := new(big.Int) |
|
| 780 |
+ wrappedMask.SetInt64(-1 * i) |
|
| 781 |
+ wrappedMask.Sub(wrappedMask, big.NewInt(1)) |
|
| 782 |
+ |
|
| 783 |
+ wrappedMask.AndNot(wrappedMask, mask) |
|
| 784 |
+ |
|
| 785 |
+ lastUsable := new(big.Int) |
|
| 786 |
+ lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address) |
|
| 787 |
+ |
|
| 788 |
+ ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask) |
|
| 789 |
+ } |
|
| 790 |
+ |
|
| 791 |
+ return IfAddr{
|
|
| 792 |
+ SockAddr: IPv6Addr{
|
|
| 793 |
+ Address: IPv6Address(ipv6BigInt), |
|
| 794 |
+ Mask: ipv6.Mask, |
|
| 795 |
+ }, |
|
| 796 |
+ Interface: inputIfAddr.Interface, |
|
| 797 |
+ }, nil |
|
| 798 |
+ default: |
|
| 799 |
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
|
| 800 |
+ } |
|
| 801 |
+ case "mask": |
|
| 802 |
+ // "mask" operates on the IP address and returns the IP address on |
|
| 803 |
+ // which the given integer mask has been applied. If the applied mask |
|
| 804 |
+ // corresponds to a larger network than the mask of the IP address, |
|
| 805 |
+ // the latter will be replaced by the former. |
|
| 806 |
+ switch sockType := inputIfAddr.SockAddr.Type(); sockType {
|
|
| 807 |
+ case TypeIPv4: |
|
| 808 |
+ i, err := strconv.ParseUint(value, 10, 32) |
|
| 809 |
+ if err != nil {
|
|
| 810 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 811 |
+ } |
|
| 812 |
+ |
|
| 813 |
+ if i > 32 {
|
|
| 814 |
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
|
|
| 815 |
+ } |
|
| 816 |
+ |
|
| 817 |
+ ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) |
|
| 818 |
+ |
|
| 819 |
+ ipv4Mask := net.CIDRMask(int(i), 32) |
|
| 820 |
+ ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask) |
|
| 821 |
+ |
|
| 822 |
+ maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask) |
|
| 823 |
+ maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4) |
|
| 824 |
+ |
|
| 825 |
+ maskedIpv4MaskUint32 := uint32(ipv4.Mask) |
|
| 826 |
+ |
|
| 827 |
+ if ipv4MaskUint32 < maskedIpv4MaskUint32 {
|
|
| 828 |
+ maskedIpv4MaskUint32 = ipv4MaskUint32 |
|
| 829 |
+ } |
|
| 830 |
+ |
|
| 831 |
+ return IfAddr{
|
|
| 832 |
+ SockAddr: IPv4Addr{
|
|
| 833 |
+ Address: IPv4Address(maskedIpv4Uint32), |
|
| 834 |
+ Mask: IPv4Mask(maskedIpv4MaskUint32), |
|
| 835 |
+ }, |
|
| 836 |
+ Interface: inputIfAddr.Interface, |
|
| 837 |
+ }, nil |
|
| 838 |
+ case TypeIPv6: |
|
| 839 |
+ i, err := strconv.ParseUint(value, 10, 32) |
|
| 840 |
+ if err != nil {
|
|
| 841 |
+ return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
|
| 842 |
+ } |
|
| 843 |
+ |
|
| 844 |
+ if i > 128 {
|
|
| 845 |
+ return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
|
|
| 846 |
+ } |
|
| 847 |
+ |
|
| 848 |
+ ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) |
|
| 849 |
+ |
|
| 850 |
+ ipv6Mask := net.CIDRMask(int(i), 128) |
|
| 851 |
+ ipv6MaskBigInt := new(big.Int) |
|
| 852 |
+ ipv6MaskBigInt.SetBytes(ipv6Mask) |
|
| 853 |
+ |
|
| 854 |
+ maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask) |
|
| 855 |
+ maskedIpv6BigInt := new(big.Int) |
|
| 856 |
+ maskedIpv6BigInt.SetBytes(maskedIpv6) |
|
| 857 |
+ |
|
| 858 |
+ maskedIpv6MaskBigInt := new(big.Int) |
|
| 859 |
+ maskedIpv6MaskBigInt.Set(ipv6.Mask) |
|
| 860 |
+ |
|
| 861 |
+ if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
|
|
| 862 |
+ maskedIpv6MaskBigInt = ipv6MaskBigInt |
|
| 863 |
+ } |
|
| 864 |
+ |
|
| 865 |
+ return IfAddr{
|
|
| 866 |
+ SockAddr: IPv6Addr{
|
|
| 867 |
+ Address: IPv6Address(maskedIpv6BigInt), |
|
| 868 |
+ Mask: IPv6Mask(maskedIpv6MaskBigInt), |
|
| 869 |
+ }, |
|
| 870 |
+ Interface: inputIfAddr.Interface, |
|
| 871 |
+ }, nil |
|
| 872 |
+ default: |
|
| 873 |
+ return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
|
| 874 |
+ } |
|
| 875 |
+ default: |
|
| 876 |
+ return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
|
|
| 877 |
+ } |
|
| 878 |
+} |
|
| 879 |
+ |
|
| 880 |
+// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any |
|
| 881 |
+// failure will result in zero results. |
|
| 882 |
+func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) {
|
|
| 883 |
+ outputAddrs := make(IfAddrs, 0, len(inputIfAddrs)) |
|
| 884 |
+ for _, ifAddr := range inputIfAddrs {
|
|
| 885 |
+ result, err := IfAddrMath(operation, value, ifAddr) |
|
| 886 |
+ if err != nil {
|
|
| 887 |
+ return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err)
|
|
| 888 |
+ } |
|
| 889 |
+ outputAddrs = append(outputAddrs, result) |
|
| 890 |
+ } |
|
| 891 |
+ return outputAddrs, nil |
|
| 892 |
+} |
|
| 893 |
+ |
|
| 655 | 894 |
// IncludeIfs returns an IfAddrs based on the passed in selector. |
| 656 | 895 |
func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
|
| 657 | 896 |
var includedIfs IfAddrs |
| ... | ... |
@@ -736,6 +1044,10 @@ func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
|
| 736 | 736 |
sortFuncs[i] = AscIfAddress |
| 737 | 737 |
case "-address": |
| 738 | 738 |
sortFuncs[i] = DescIfAddress |
| 739 |
+ case "+default", "default": |
|
| 740 |
+ sortFuncs[i] = AscIfDefault |
|
| 741 |
+ case "-default": |
|
| 742 |
+ sortFuncs[i] = DescIfDefault |
|
| 739 | 743 |
case "+name", "name": |
| 740 | 744 |
// The "name" selector returns an array of IfAddrs |
| 741 | 745 |
// ordered by the interface name. |
| ... | ... |
@@ -886,7 +1198,7 @@ func parseDefaultIfNameFromRoute(routeOut string) (string, error) {
|
| 886 | 886 |
// Linux. |
| 887 | 887 |
func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
|
| 888 | 888 |
lines := strings.Split(routeOut, "\n") |
| 889 |
- re := regexp.MustCompile(`[\s]+`) |
|
| 889 |
+ re := whitespaceRE.Copy() |
|
| 890 | 890 |
for _, line := range lines {
|
| 891 | 891 |
kvs := re.Split(line, -1) |
| 892 | 892 |
if len(kvs) < 5 {
|
| ... | ... |
@@ -929,7 +1241,7 @@ func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) {
|
| 929 | 929 |
// support added. |
| 930 | 930 |
func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
|
| 931 | 931 |
lines := strings.Split(routeOut, "\n") |
| 932 |
- re := regexp.MustCompile(`[\s]+`) |
|
| 932 |
+ re := whitespaceRE.Copy() |
|
| 933 | 933 |
for _, line := range lines {
|
| 934 | 934 |
kvs := re.Split(strings.TrimSpace(line), -1) |
| 935 | 935 |
if len(kvs) < 3 {
|
| ... | ... |
@@ -949,17 +1261,17 @@ func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
|
| 949 | 949 |
// interface name forwarding traffic to the default gateway. |
| 950 | 950 |
func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
|
| 951 | 951 |
lines := strings.Split(routeOut, "\n") |
| 952 |
- ifNameRE := regexp.MustCompile(`^Ethernet adapter ([^\s:]+):`) |
|
| 953 |
- ipAddrRE := regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) |
|
| 952 |
+ ifNameRe := ifNameRE.Copy() |
|
| 953 |
+ ipAddrRe := ipAddrRE.Copy() |
|
| 954 | 954 |
var ifName string |
| 955 | 955 |
for _, line := range lines {
|
| 956 |
- switch ifNameMatches := ifNameRE.FindStringSubmatch(line); {
|
|
| 956 |
+ switch ifNameMatches := ifNameRe.FindStringSubmatch(line); {
|
|
| 957 | 957 |
case len(ifNameMatches) > 1: |
| 958 | 958 |
ifName = ifNameMatches[1] |
| 959 | 959 |
continue |
| 960 | 960 |
} |
| 961 | 961 |
|
| 962 |
- switch ipAddrMatches := ipAddrRE.FindStringSubmatch(line); {
|
|
| 962 |
+ switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); {
|
|
| 963 | 963 |
case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr: |
| 964 | 964 |
return ifName, nil |
| 965 | 965 |
} |
| ... | ... |
@@ -58,7 +58,8 @@ func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) {
|
| 58 | 58 |
// Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In |
| 59 | 59 |
// particular, clients with the Barracuda VPN client will see something like: |
| 60 | 60 |
// `192.168.3.51/00ffffff` as their IP address. |
| 61 |
- if match := trailingHexNetmaskRE.FindStringIndex(ipv4Str); match != nil {
|
|
| 61 |
+ trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() |
|
| 62 |
+ if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil {
|
|
| 62 | 63 |
ipv4Str = ipv4Str[:match[0]] |
| 63 | 64 |
} |
| 64 | 65 |
|
| ... | ... |
@@ -3,6 +3,7 @@ package sockaddr |
| 3 | 3 |
// ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP |
| 4 | 4 |
// blocks. |
| 5 | 5 |
const ForwardingBlacklist = 4294967295 |
| 6 |
+const ForwardingBlacklistRFC = "4294967295" |
|
| 6 | 7 |
|
| 7 | 8 |
// IsRFC tests to see if an SockAddr matches the specified RFC |
| 8 | 9 |
func IsRFC(rfcNum uint, sa SockAddr) bool {
|
| ... | ... |
@@ -5,10 +5,6 @@ import ( |
| 5 | 5 |
"os/exec" |
| 6 | 6 |
) |
| 7 | 7 |
|
| 8 |
-var cmds map[string][]string = map[string][]string{
|
|
| 9 |
- "ip": {"/sbin/ip", "route"},
|
|
| 10 |
-} |
|
| 11 |
- |
|
| 12 | 8 |
type routeInfo struct {
|
| 13 | 9 |
cmds map[string][]string |
| 14 | 10 |
} |
| ... | ... |
@@ -16,15 +12,22 @@ type routeInfo struct {
|
| 16 | 16 |
// NewRouteInfo returns a Linux-specific implementation of the RouteInfo |
| 17 | 17 |
// interface. |
| 18 | 18 |
func NewRouteInfo() (routeInfo, error) {
|
| 19 |
+ // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on |
|
| 20 |
+ // $PATH and fallback to /sbin/ip on error. |
|
| 21 |
+ path, _ := exec.LookPath("ip")
|
|
| 22 |
+ if path == "" {
|
|
| 23 |
+ path = "/sbin/ip" |
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 19 | 26 |
return routeInfo{
|
| 20 |
- cmds: cmds, |
|
| 27 |
+ cmds: map[string][]string{"ip": {path, "route"}},
|
|
| 21 | 28 |
}, nil |
| 22 | 29 |
} |
| 23 | 30 |
|
| 24 | 31 |
// GetDefaultInterfaceName returns the interface name attached to the default |
| 25 | 32 |
// route on the default interface. |
| 26 | 33 |
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
|
| 27 |
- out, err := exec.Command(cmds["ip"][0], cmds["ip"][1:]...).Output() |
|
| 34 |
+ out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() |
|
| 28 | 35 |
if err != nil {
|
| 29 | 36 |
return "", err |
| 30 | 37 |
} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package sockaddr |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "encoding/json" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"strings" |
| 6 | 7 |
) |
| ... | ... |
@@ -176,3 +177,30 @@ func sockAddrInit() {
|
| 176 | 176 |
func SockAddrAttrs() []AttrName {
|
| 177 | 177 |
return sockAddrAttrs |
| 178 | 178 |
} |
| 179 |
+ |
|
| 180 |
+// Although this is pretty trivial to do in a program, having the logic here is |
|
| 181 |
+// useful all around. Note that this marshals into a *string* -- the underlying |
|
| 182 |
+// string representation of the sockaddr. If you then unmarshal into this type |
|
| 183 |
+// in Go, all will work as expected, but externally you can take what comes out |
|
| 184 |
+// and use the string value directly. |
|
| 185 |
+type SockAddrMarshaler struct {
|
|
| 186 |
+ SockAddr |
|
| 187 |
+} |
|
| 188 |
+ |
|
| 189 |
+func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) {
|
|
| 190 |
+ return json.Marshal(s.SockAddr.String()) |
|
| 191 |
+} |
|
| 192 |
+ |
|
| 193 |
+func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error {
|
|
| 194 |
+ var str string |
|
| 195 |
+ err := json.Unmarshal(in, &str) |
|
| 196 |
+ if err != nil {
|
|
| 197 |
+ return err |
|
| 198 |
+ } |
|
| 199 |
+ sa, err := NewSockAddr(str) |
|
| 200 |
+ if err != nil {
|
|
| 201 |
+ return err |
|
| 202 |
+ } |
|
| 203 |
+ s.SockAddr = sa |
|
| 204 |
+ return nil |
|
| 205 |
+} |