diff options
Diffstat (limited to 'vendor/github.com/hashicorp/go-sockaddr')
21 files changed, 1099 insertions, 83 deletions
diff --git a/vendor/github.com/hashicorp/go-sockaddr/Makefile b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile index 224135dc1..f3dfd24cf 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/Makefile +++ b/vendor/github.com/hashicorp/go-sockaddr/GNUmakefile @@ -2,6 +2,8 @@ TOOLS= golang.org/x/tools/cover GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp GOCOVER_FILE?= .cover.out GOCOVERHTML?= coverage.html +FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1` +XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1` test:: $(GOCOVER_FILE) @$(MAKE) -C cmd/sockaddr test @@ -9,10 +11,10 @@ test:: $(GOCOVER_FILE) cover:: coverage_report $(GOCOVER_FILE):: - @find . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | xargs -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)" + @${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)" @echo 'mode: set' > $(GOCOVER_FILE) - @find . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | xargs -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE) + @${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE) $(GOCOVERHTML): $(GOCOVER_FILE) go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML) @@ -41,15 +43,15 @@ clean:: dev:: @go build - @make -B -C cmd/sockaddr sockaddr + @$(MAKE) -B -C cmd/sockaddr sockaddr install:: @go install - @make -C cmd/sockaddr install + @$(MAKE) -C cmd/sockaddr install doc:: - echo Visit: http://127.0.0.1:6060/pkg/github.com/hashicorp/go-sockaddr/ - godoc -http=:6060 -goroot $GOROOT + @echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/ + godoc -http=:6161 -goroot $GOROOT world:: @set -e; \ @@ -60,4 +62,4 @@ world:: done; \ done - make -C cmd/sockaddr world + $(MAKE) -C cmd/sockaddr world diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/GNUmakefile b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/GNUmakefile index 90232d2f0..6d0039ae5 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/GNUmakefile +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/GNUmakefile @@ -21,7 +21,7 @@ install:: $(BIN) .PHONY: test test:: $(BIN) - @make -C regression + @$(MAKE) -C regression .PHONY: world world:: diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/README.md b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/README.md index cc247afb5..e9914ffc1 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/README.md +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/README.md @@ -119,7 +119,7 @@ Options: Here are a few impractical examples to get you started: ```text -$ sockaddr eval 'GetDefaultInterfaces | sort "type,size" | include "RFC" "6890" | attr "address"' +$ sockaddr eval 'GetAllInterfaces | include "flags" "forwardable" | include "up" | sort "default,type,size" | include "RFC" "6890" | attr "address"' 172.14.6.167 $ sockaddr eval 'GetDefaultInterfaces | sort "type,size" | include "RFC" "6890" | limit 1 | join "address" " "' 172.14.6.167 @@ -133,7 +133,7 @@ $ sockaddr eval 'GetAllInterfaces | include "network" "172.14.6.0/24" | attr "ad 172.14.6.167 $ sockaddr eval 'GetPrivateInterfaces | join "type" " "' IPv4 IPv6 -$ sockaddr eval 'GetPublicInterfaces | include "flags" "up|forwardable" | join "address" " "' +$ sockaddr eval 'GetAllInterfaces | include "flags" "forwardable" | join "address" " "' 203.0.113.4 2001:0DB8::1 $ sockaddr eval 'GetAllInterfaces | include "name" "lo0" | include "type" "IPv6" | sort "address" | join "address" " "' 100:: fe80::1 @@ -147,6 +147,11 @@ $ cat <<'EOF' | sockaddr eval - {{. | include "name" "lo0" | include "type" "IPv6" | sort "address" | join "address" " "}} EOF 100:: fe80::1 +$ sockaddr eval 'GetPrivateInterfaces | include "flags" "forwardable|up" | include "type" "IPv4" | math "network" "+2" | attr "address"' +172.14.6.2 +$ cat <<'EOF' | sudo tee -a /etc/profile +export CONSUL_HTTP_ADDR="http://`sockaddr eval 'GetInterfaceIP \"eth0\"'`:8500" +EOF ``` ## `sockaddr rfc` diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr.out b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr.out index b836500e5..858f1516e 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr.out +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr.out @@ -1,4 +1,4 @@ -usage: sockaddr [--version] [--help] <command> [<args>] +Usage: sockaddr [--version] [--help] <command> [<args>] Available commands are: dump Parses input as an IP or interface name(s) and dumps various information diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-00.out b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-00.out index d638c462a..82f4f4e13 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-00.out +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-00.out @@ -10,6 +10,4 @@ Options: -s Silent, only return different exit codes Subcommands: - list Lists all known RFCs - diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-01.out b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-01.out index 555d039c8..82f4f4e13 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-01.out +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/expected/sockaddr_rfc-01.out @@ -8,3 +8,6 @@ Usage: sockaddr rfc [RFC Number] [IP Address] Options: -s Silent, only return different exit codes + +Subcommands: + list Lists all known RFCs diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/run_all.sh b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/run_all.sh index 4b6d8a746..9fa39ee9e 100755 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/run_all.sh +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/regression/run_all.sh @@ -1,11 +1,13 @@ #!/bin/sh -- +FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1` +XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1` set -e set -u num_cpus=$(getconf NPROCESSORS_ONLN) set +e -find . -name 'test_*.sh' -depth 1 | xargs -n1 -P${num_cpus} ./run_one.sh +${FIND} . -maxdepth 1 -name 'test_*.sh' -print0 | ${XARGS} -0 -n1 -P${num_cpus} ./run_one.sh set -e # rune_one.sh generates the .diff files diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/README.md b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/README.md index 1f69ccb20..dd211cf0e 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/README.md +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/README.md @@ -5,6 +5,7 @@ cli is the library that powers the CLI for [Packer](https://github.com/mitchellh/packer), [Serf](https://github.com/hashicorp/serf), [Consul](https://github.com/hashicorp/consul), +[Vault](https://github.com/hashicorp/vault), [Terraform](https://github.com/hashicorp/terraform), and [Nomad](https://github.com/hashicorp/nomad). diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/cli.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/cli.go index 353edb6c2..4a69d176d 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/cli.go +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/github.com/mitchellh/cli/cli.go @@ -120,7 +120,13 @@ func (c *CLI) Run() (int, error) { // Just show the version and exit if instructed. if c.IsVersion() && c.Version != "" { c.HelpWriter.Write([]byte(c.Version + "\n")) - return 1, nil + return 0, nil + } + + // Just print the help when only '-h' or '--help' is passed. + if c.IsHelp() && c.Subcommand() == "" { + c.HelpWriter.Write([]byte(c.HelpFunc(c.Commands) + "\n")) + return 0, nil } // Attempt to get the factory function for creating the command @@ -133,13 +139,13 @@ func (c *CLI) Run() (int, error) { command, err := raw.(CommandFactory)() if err != nil { - return 0, err + return 1, err } // If we've been instructed to just print the help, then print it if c.IsHelp() { c.commandHelp(command) - return 1, nil + return 0, nil } // If there is an invalid flag, then error @@ -454,7 +460,7 @@ const defaultHelpTemplate = ` {{.Help}}{{if gt (len .Subcommands) 0}} Subcommands: -{{ range $value := .Subcommands }} +{{- range $value := .Subcommands }} {{ $value.NameAligned }} {{ $value.Synopsis }}{{ end }} -{{ end }} +{{- end }} ` diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/vendor.json b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/vendor.json index 7514b1ac4..cc56af3f9 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/vendor.json +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/vendor/vendor.json @@ -27,10 +27,10 @@ "revisionTime": "2016-08-06T12:27:52Z" }, { - "checksumSHA1": "W6WsJ7dtBT0coA3S5FpGR0k4IEU=", + "checksumSHA1": "UP+pXl+ic9y6qrpZA5MqDIAuGfw=", "path": "github.com/mitchellh/cli", - "revision": "494eb006fe29e9dc75fea6da4df4818f7e046b73", - "revisionTime": "2017-02-08T07:23:55Z" + "revision": "ee8578a9c12a5bb9d55303b9665cc448772c81b8", + "revisionTime": "2017-03-28T05:23:52Z" }, { "checksumSHA1": "L3leymg2RT8hFl5uL+5KP/LpBkg=", diff --git a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/version.go b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/version.go index 32cac2d47..10da3e698 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/version.go +++ b/vendor/github.com/hashicorp/go-sockaddr/cmd/sockaddr/version.go @@ -12,7 +12,7 @@ var ( ) // The main version number that is being run at the moment. -const Version = "0.1.0" +const Version = "0.2.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go index 3e4ff9fca..0811b2759 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" <<ARG>> | 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/ifaddr_test.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go index 9737ef35c..859c3e421 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go @@ -45,6 +45,42 @@ func havePublicIP() bool { return boolEnvVar("SOCKADDR_HAVE_PUBLIC_IP", false) } +func TestGetPrivateIP(t *testing.T) { + reportOnPrivate := func(args ...interface{}) { + if havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + ip, err := sockaddr.GetPrivateIP() + if err != nil { + reportOnPrivate("unable to get a private IP: %v", err) + } + + if ip == "" { + reportOnPrivate("it's hard to test this reliably") + } +} + +func TestGetPrivateIPs(t *testing.T) { + reportOnPrivate := func(args ...interface{}) { + if havePrivateIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + ips, err := sockaddr.GetPrivateIPs() + if err != nil { + reportOnPrivate("unable to get a private IPs: %v", err) + } + + if ips == "" { + reportOnPrivate("it's hard to test this reliably") + } +} + func TestGetPublicIP(t *testing.T) { reportOnPublic := func(args ...interface{}) { if havePublicIP() { @@ -63,6 +99,24 @@ func TestGetPublicIP(t *testing.T) { } } +func TestGetPublicIPs(t *testing.T) { + reportOnPublic := func(args ...interface{}) { + if havePublicIP() { + t.Fatalf(args[0].(string), args[1:]...) + } else { + t.Skipf(args[0].(string), args[1:]...) + } + } + ips, err := sockaddr.GetPublicIPs() + if err != nil { + reportOnPublic("unable to get a public IPs: %v", err) + } + + if ips == "" { + reportOnPublic("it's hard to test this reliably") + } +} + func TestGetInterfaceIP(t *testing.T) { ip, err := sockaddr.GetInterfaceIP(`^.*[\d]$`) if err != nil { @@ -98,7 +152,7 @@ func TestIfAddrAttr(t *testing.T) { t.Fatalf("test %d must have a name", i) } - result, err := sockaddr.IfAttr(test.attr, sockaddr.IfAddrs{test.ifAddr}) + result, err := sockaddr.IfAttr(test.attr, test.ifAddr) if err != nil { t.Errorf("failed to get attr %q from %v", test.name, test.ifAddr) } @@ -107,14 +161,317 @@ func TestIfAddrAttr(t *testing.T) { t.Errorf("unexpected result") } } +} - // Test an empty array - result, err := sockaddr.IfAttr("name", sockaddr.IfAddrs{}) - if err != nil { - t.Error(`failed to get attr "name" from an empty array`) +func TestIfAddrMath(t *testing.T) { + tests := []struct { + name string + ifAddr sockaddr.IfAddr + operation string + value string + expected string + wantFail bool + }{ + { + name: "ipv4 address +2", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: "+2", + expected: "127.0.0.3/8", + }, + { + name: "ipv4 address -2", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: "-2", + expected: "126.255.255.255/8", + }, + { + name: "ipv4 address + overflow 0xff00ff03", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: fmt.Sprintf("+%d", 0xff00ff03), + expected: "126.0.255.4/8", + }, + { + name: "ipv4 address - underflow 0xff00ff04", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: fmt.Sprintf("-%d", 0xff00ff04), + expected: "127.255.0.253/8", + }, + { + name: "ipv6 address +2", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "address", + value: "+2", + expected: "::3", + }, + { + name: "ipv6 address -3", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::4/128"), + }, + operation: "address", + value: "-3", + expected: "::1", + }, + { + name: "ipv6 address + overflow", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"), + }, + operation: "address", + value: fmt.Sprintf("+%d", 0x03), + expected: "::2", + }, + { + name: "ipv6 address + underflow", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "address", + value: fmt.Sprintf("-%d", 0x03), + expected: "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe", + }, + { + name: "ipv4 network +2", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: "+2", + expected: "127.0.0.2/8", + }, + { + name: "ipv4 network -2", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: "-2", + expected: "127.255.255.254/8", + }, + { + // Value exceeds /8 + name: "ipv4 network + overflow 0xff00ff03", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: fmt.Sprintf("+%d", 0xff00ff03), + expected: "127.0.255.3/8", + }, + { + // Value exceeds /8 + name: "ipv4 network - underflow+wrap 0xff00ff04", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: fmt.Sprintf("-%d", 0xff00ff04), + expected: "127.255.0.252/8", + }, + { + name: "ipv6 network +6", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("fe80::1/64"), + }, + operation: "network", + value: "+6", + expected: "fe80::6/64", + }, + { + name: "ipv6 network -6", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("fe80::ff/64"), + }, + operation: "network", + value: "-6", + expected: "fe80::ffff:ffff:ffff:fffa/64", + }, + { + // Value exceeds /104 mask + name: "ipv6 network + overflow 0xff00ff03", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("fe80::1/104"), + }, + operation: "network", + value: fmt.Sprintf("+%d", 0xff00ff03), + expected: "fe80::ff03/104", + }, + { + // Value exceeds /104 + name: "ipv6 network - underflow+wrap 0xff00ff04", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("fe80::1/104"), + }, + operation: "network", + value: fmt.Sprintf("-%d", 0xff00ff04), + expected: "fe80::ff:fc/104", + }, + { + name: "ipv4 address missing sign", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: "123", + wantFail: true, + }, + { + name: "ipv4 network missing sign", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: "123", + wantFail: true, + }, + { + name: "ipv6 address missing sign", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "address", + value: "123", + wantFail: true, + }, + { + name: "ipv6 network missing sign", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "network", + value: "123", + wantFail: true, + }, + { + name: "ipv4 address bad value", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "address", + value: "+xyz", + wantFail: true, + }, + { + name: "ipv4 network bad value", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "network", + value: "-xyz", + wantFail: true, + }, + { + name: "ipv6 address bad value", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "address", + value: "+xyz", + wantFail: true, + }, + { + name: "ipv6 network bad value", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "network", + value: "-xyz", + wantFail: true, + }, + { + name: "ipv4 bad operation", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"), + }, + operation: "gooz", + value: "+xyz", + wantFail: true, + }, + { + name: "ipv6 bad operation", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv6Addr("::1/128"), + }, + operation: "frabba", + value: "+xyz", + wantFail: true, + }, + { + name: "unix unsupported operation", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustUnixSock("/tmp/bar"), + }, + operation: "address", + value: "+123", + wantFail: true, + }, + { + name: "unix unsupported operation", + ifAddr: sockaddr.IfAddr{ + SockAddr: sockaddr.MustUnixSock("/tmp/foo"), + }, + operation: "network", + value: "+123", + wantFail: true, + }, } - if result != "" { - t.Errorf("unexpected result") + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + + results, err := sockaddr.IfAddrsMath(test.operation, test.value, sockaddr.IfAddrs{test.ifAddr}) + if test.wantFail { + if err != nil { + continue + } else { + t.Fatalf("%s: failed to fail math operation %q with value %q on %v", test.name, test.operation, test.value, test.ifAddr) + } + } else if err != nil { + t.Fatalf("%s: failed to compute math operation %q with value %q on %v", test.name, test.operation, test.value, test.ifAddr) + } + if len(results) != 1 { + t.Fatalf("%s: bad", test.name) + } + + result := results[0] + + switch saType := result.Type(); saType { + case sockaddr.TypeIPv4: + ipv4 := sockaddr.ToIPv4Addr(result.SockAddr) + if ipv4 == nil { + t.Fatalf("bad: %T %+#v", result, result) + } + + if got := ipv4.String(); got != test.expected { + t.Errorf("unexpected result %q: want %q got %q", test.name, test.expected, got) + } + case sockaddr.TypeIPv6: + ipv6 := sockaddr.ToIPv6Addr(result.SockAddr) + if ipv6 == nil { + t.Fatalf("bad: %T %+#v", result, result) + } + + if got := ipv6.String(); got != test.expected { + t.Errorf("unexpected result %q: want %q got %q", test.name, test.expected, got) + } + default: + t.Fatalf("bad") + } } } diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go index 8233be202..b87589a22 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go @@ -3,6 +3,7 @@ package sockaddr import ( "errors" "fmt" + "math/big" "net" "regexp" "sort" @@ -10,6 +11,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 adapter ([^\s:]+):`) + ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) +) + // IfAddrs is a slice of IfAddr type IfAddrs []IfAddr @@ -91,6 +100,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 +170,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 +217,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 +299,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 +315,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 +347,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 +363,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 +720,171 @@ 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) + } + 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 +969,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 +1123,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 +1166,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 +1186,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/ifaddrs_test.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go index e89dae1ef..aed847808 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go +++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs_test.go @@ -9,6 +9,13 @@ import ( sockaddr "github.com/hashicorp/go-sockaddr" ) +const ( + // NOTE(seanc@): Assume "en0" is the interface with a default route attached + // to it. When this is not the case, change this one constant and tests + // should pass (i.e. "net0"). + ifNameWithDefault = "en0" +) + // NOTE: A number of these code paths are exercised in template/ and // cmd/sockaddr/. // @@ -690,30 +697,54 @@ func TestGetDefaultInterface(t *testing.T) { } } -func TestGetPrivateIP(t *testing.T) { - reportOnPrivate := func(args ...interface{}) { - if havePrivateIP() { - t.Fatalf(args[0].(string), args[1:]...) - } else { - t.Skipf(args[0].(string), args[1:]...) - } +func TestIfAddrAttrs(t *testing.T) { + const expectedNumAttrs = 2 + attrs := sockaddr.IfAddrAttrs() + if len(attrs) != expectedNumAttrs { + t.Fatalf("wrong number of attrs") } - ip, err := sockaddr.GetPrivateIP() - if err != nil { - reportOnPrivate("private IP failed: %v", err) + tests := []struct { + name string + ifAddr sockaddr.IfAddr + attr string + expected string + }{ + { + name: "name", + ifAddr: sockaddr.IfAddr{ + Interface: net.Interface{ + Name: "abc0", + }, + }, + attr: "name", + expected: "abc0", + }, } - if len(ip) == 0 { - reportOnPrivate("no private IP found", nil) + for i, test := range tests { + if test.name == "" { + t.Fatalf("test %d must have a name", i) + } + + result, err := sockaddr.IfAttrs(test.attr, sockaddr.IfAddrs{test.ifAddr}) + if err != nil { + t.Errorf("failed to get attr %q from %v", test.name, test.ifAddr) + } + + if result != test.expected { + t.Errorf("unexpected result") + } } -} -func TestIfAddrAttrs(t *testing.T) { - const expectedNumAttrs = 2 - attrs := sockaddr.IfAddrAttrs() - if len(attrs) != expectedNumAttrs { - t.Fatalf("wrong number of attrs") + // Test an empty array + result, err := sockaddr.IfAttrs("name", sockaddr.IfAddrs{}) + if err != nil { + t.Error(`failed to get attr "name" from an empty array`) + } + + if result != "" { + t.Errorf("unexpected result") } } @@ -788,7 +819,7 @@ func TestGetPrivateInterfaces(t *testing.T) { } if len(ifAddrs) == 0 { - reportOnPrivate("no public IPs found", nil) + reportOnPrivate("no public IPs found") } if len(ifAddrs[0].String()) == 0 { @@ -1669,6 +1700,82 @@ func TestSortIfBy(t *testing.T) { }, }, { + // NOTE(seanc@): This test requires macOS, or at least a computer where + // en0 has the default route. + name: "sort default", + sortStr: "default", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: "other0"}, + }, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: "other0"}, + }, + }, + }, + { + // NOTE(seanc@): This test requires macOS, or at least a computer where + // en0 has the default route. + name: "sort +default", + sortStr: "+default", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: "other0"}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: "other0"}, + }, + }, + }, + { + name: "sort -default", + sortStr: "-default", + in: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: "other0"}, + }, + }, + out: sockaddr.IfAddrs{ + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.4"), + Interface: net.Interface{Name: "other0"}, + }, + sockaddr.IfAddr{ + SockAddr: sockaddr.MustIPv4Addr("1.2.3.3"), + Interface: net.Interface{Name: ifNameWithDefault}, + }, + }, + }, + { name: "sort name", sortStr: "name", in: sockaddr.IfAddrs{ @@ -1877,5 +1984,4 @@ func TestSortIfBy(t *testing.T) { } }) } - } diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go index 9f2616a69..4d395dc95 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 fd9be940b..02e188f6f 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/template/Makefile b/vendor/github.com/hashicorp/go-sockaddr/template/GNUmakefile index ce1e274e4..ce1e274e4 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/template/Makefile +++ b/vendor/github.com/hashicorp/go-sockaddr/template/GNUmakefile diff --git a/vendor/github.com/hashicorp/go-sockaddr/template/doc.go b/vendor/github.com/hashicorp/go-sockaddr/template/doc.go index 59945d7be..90c8784a3 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/template/doc.go +++ b/vendor/github.com/hashicorp/go-sockaddr/template/doc.go @@ -53,23 +53,22 @@ Example: {{ GetDefaultInterfaces }} `GetPrivateInterfaces` - Returns one IfAddr for every forwardable IP address -that is included in RFC 6890, is attached to the interface with the default -route, and whose interface is marked as up. NOTE: RFC 6890 is a more exhaustive -version of RFC1918 because it spans IPv4 and IPv6, however it does permit the +that is included in RFC 6890 and whose interface is marked as up. NOTE: RFC 6890 is a more exhaustive +version of RFC1918 because it spans IPv4 and IPv6, however, RFC6890 does permit the inclusion of likely undesired addresses such as multicast, therefore our version of "private" also filters out non-forwardable addresses. Example: - {{ GetPrivateInterfaces | include "flags" "up" }} + {{ GetPrivateInterfaces | sort "default" | join "address" " " }} -`GetPublicInterfaces` - Returns a list of IfAddr that do not match RFC 6890, is -attached to the default route, and whose interface is marked as up. +`GetPublicInterfaces` - Returns a list of IfAddr structs whos IPs are +forwardable, do not match RFC 6890, and whose interface is marked up. Example: - {{ GetPublicInterfaces | include "flags" "up" }} + {{ GetPublicInterfaces | sort "default" | join "name" " " }} `GetPrivateIP` - Helper function that returns a string of the first IP address @@ -80,6 +79,14 @@ Example: {{ GetPrivateIP }} +`GetPrivateIPs` - Helper function that returns a string of the all private IP +addresses on the host. + +Example: + + {{ GetPrivateIPs }} + + `GetPublicIP` - Helper function that returns a string of the first IP from GetPublicInterfaces. @@ -87,12 +94,29 @@ Example: {{ GetPublicIP }} +`GetPublicIPs` - Helper function that returns a space-delimited string of the +all public IP addresses on the host. + +Example: + + {{ GetPrivateIPs }} + + `GetInterfaceIP` - Helper function that returns a string of the first IP from the named interface. Example: - {{ GetInterfaceIP }} + {{ GetInterfaceIP "en0" }} + + + +`GetInterfaceIPs` - Helper function that returns a space-delimited list of all +IPs on a given interface. + +Example: + + {{ GetInterfaceIPs "en0" }} `sort` - Sorts the IfAddrs result based on its arguments. `sort` takes one @@ -100,6 +124,8 @@ argument, a list of ways to sort its IfAddrs argument. The list of sort criteria is comma separated (`,`): - `address`, `+address`: Ascending sort of IfAddrs by Address - `-address`: Descending sort of IfAddrs by Address + - `default`, `+default`: Ascending sort of IfAddrs, IfAddr with a default route first + - `-default`: Descending sort of IfAddrs, IfAttr with default route last - `name`, `+name`: Ascending sort of IfAddrs by lexical ordering of interface name - `-name`: Descending sort of IfAddrs by lexical ordering of interface name - `port`, `+port`: Ascending sort of IfAddrs by port number @@ -116,7 +142,7 @@ criteria is comma separated (`,`): Example: - {{ GetPrivateInterfaces | sort "type,size,address" }} + {{ GetPrivateInterfaces | sort "default,-type,size,+address" }} `exclude` and `include`: Filters IfAddrs based on the selector criteria and its @@ -142,7 +168,7 @@ available filtering criteria is: Example: - {{ GetPrivateInterfaces | exclude "type" "IPv6" | include "flag" "up|forwardable" }} + {{ GetPrivateInterfaces | exclude "type" "IPv6" }} `unique`: Removes duplicate entries from the IfAddrs list, assuming the list has @@ -152,14 +178,14 @@ already been sorted. `unique` only takes one argument: Example: - {{ GetPrivateInterfaces | sort "type,address" | unique "name" }} + {{ GetAllInterfaces | sort "default,-type,address" | unique "name" }} `limit`: Reduces the size of the list to the specified value. Example: - {{ GetPrivateInterfaces | include "flags" "forwardable|up" | limit 1 }} + {{ GetPrivateInterfaces | limit 1 }} `offset`: Seeks into the list by the specified value. A negative value can be @@ -167,7 +193,33 @@ used to seek from the end of the list. Example: - {{ GetPrivateInterfaces | include "flags" "forwardable|up" | offset "-2" | limit 1 }} + {{ GetPrivateInterfaces | offset "-2" | limit 1 }} + + +`math`: Perform a "math" operation on each member of the list and return new +values. `math` takes two arguments, the attribute to operate on and the +operation's value. + +Supported operations include: + + - `address`: Adds the value, a positive or negative value expressed as a + decimal string, to the address. The sign is required. This value is + allowed to over or underflow networks (e.g. 127.255.255.255 `"address" "+1"` + will return "128.0.0.0"). Addresses will wrap at IPv4 or IPv6 boundaries. + - `network`: Add the value, a positive or negative value expressed as a + decimal string, to the network address. The sign is required. Positive + values are added to the network address. Negative values are subtracted + from the network's broadcast address (e.g. 127.0.0.1 `"network" "-1"` will + return "127.255.255.255"). Values that overflow the network size will + safely wrap. + +Example: + + {{ GetPrivateInterfaces | include "type" "IP" | math "address" "+256" | attr "address" }} + {{ GetPrivateInterfaces | include "type" "IP" | math "address" "-256" | attr "address" }} + {{ GetPrivateInterfaces | include "type" "IP" | math "network" "+2" | attr "address" }} + {{ GetPrivateInterfaces | include "type" "IP" | math "network" "-2" | attr "address" }} + {{ GetPrivateInterfaces | include "flags" "forwardable|up" | include "type" "IPv4" | math "network" "+2" | attr "address" }} `attr`: Extracts a single attribute of the first member of the list and returns @@ -177,7 +229,19 @@ supported attributes. Example: - {{ GetPrivateInterfaces | include "flags" "forwardable|up" | attr "address" }} + {{ GetAllInterfaces | exclude "flags" "up" | attr "address" }} + + +`Attr`: Extracts a single attribute from an `IfAttr` and in every other way +performs the same as the `attr`. + +Example: + + {{ with $ifAddrs := GetAllInterfaces | include "type" "IP" | sort "+type,+address" -}} + {{- range $ifAddrs -}} + {{- Attr "address" . }} -- {{ Attr "network" . }}/{{ Attr "size" . -}} + {{- end -}} + {{- end }} `join`: Similar to `attr`, `join` extracts all matching attributes of the list @@ -187,7 +251,7 @@ and returns them as a string joined by the separator, the second argument to Example: - {{ GetPrivateInterfaces | include "flags" "forwardable|up" | join "address" " " }} + {{ GetAllInterfaces | include "flags" "forwardable" | join "address" " " }} `exclude` and `include` flags: @@ -205,7 +269,7 @@ Example: - `up`: Is the interface up? -Attributes for `attr` and `join`: +Attributes for `attr`, `Attr`, and `join`: SockAddr Type: - `string` diff --git a/vendor/github.com/hashicorp/go-sockaddr/template/template.go b/vendor/github.com/hashicorp/go-sockaddr/template/template.go index ffe467b7f..bbed51361 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/template/template.go +++ b/vendor/github.com/hashicorp/go-sockaddr/template/template.go @@ -64,23 +64,53 @@ func init() { HelperFuncs = template.FuncMap{ // Misc functions that operate on IfAddrs inputs - "attr": sockaddr.IfAttr, + "attr": Attr, "join": sockaddr.JoinIfAddrs, "limit": sockaddr.LimitIfAddrs, "offset": sockaddr.OffsetIfAddrs, "unique": sockaddr.UniqueIfAddrsBy, + // Misc math functions that operate on a single IfAddr input + "math": sockaddr.IfAddrsMath, + // Return a Private RFC 6890 IP address string that is attached // to the default route and a forwardable address. "GetPrivateIP": sockaddr.GetPrivateIP, + // Return all Private RFC 6890 IP addresses as a space-delimited string of + // IP addresses. Addresses returned do not have to be on the interface with + // a default route. + "GetPrivateIPs": sockaddr.GetPrivateIPs, + // Return a Public RFC 6890 IP address string that is attached // to the default route and a forwardable address. "GetPublicIP": sockaddr.GetPublicIP, + // Return allPublic RFC 6890 IP addresses as a space-delimited string of IP + // addresses. Addresses returned do not have to be on the interface with a + // default route. + "GetPublicIPs": sockaddr.GetPublicIPs, + // Return the first IP address of the named interface, sorted by // the largest network size. "GetInterfaceIP": sockaddr.GetInterfaceIP, + + // Return all IP addresses on the named interface, sorted by the largest + // network size. + "GetInterfaceIPs": sockaddr.GetInterfaceIPs, + } +} + +// Attr returns the attribute from the ifAddrRaw argument. If the argument is +// an IfAddrs, only the first element will be evaluated for resolution. +func Attr(selectorName string, ifAddrsRaw interface{}) (string, error) { + switch v := ifAddrsRaw.(type) { + case sockaddr.IfAddr: + return sockaddr.IfAttr(selectorName, v) + case sockaddr.IfAddrs: + return sockaddr.IfAttrs(selectorName, v) + default: + return "", fmt.Errorf("unable to obtain attribute %s from type %T (%v)", selectorName, ifAddrsRaw, ifAddrsRaw) } } diff --git a/vendor/github.com/hashicorp/go-sockaddr/template/template_test.go b/vendor/github.com/hashicorp/go-sockaddr/template/template_test.go index 6f2b47828..ec9822e77 100644 --- a/vendor/github.com/hashicorp/go-sockaddr/template/template_test.go +++ b/vendor/github.com/hashicorp/go-sockaddr/template/template_test.go @@ -181,6 +181,81 @@ func TestSockAddr_Parse(t *testing.T) { {{- end -}}`, output: `true`, }, + { + name: "math address +", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "address" "+2" | sort "+type,+address" | join "address" " " }}`, + output: `127.0.0.3 ::3 fe80::3`, + }, + { + name: "math address + overflow", + input: `|{{- with $ifAddrs := GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "address" "+16777217" | sort "+type,+address" -}} + {{- range $ifAddrs -}} + {{- attr "address" . }} -- {{ attr "network" . }}/{{ attr "size" . }}|{{ end -}} +{{- end -}}`, + output: `|128.0.0.2 -- 128.0.0.0/16777216|::100:2 -- ::100:2/1|fe80::100:2 -- fe80::/18446744073709551616|`, + }, + { + name: "math address + overflow+wrap", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "address" "+4294967294" | sort "+type,+address" | join "address" " " }}`, + output: `126.255.255.255 ::ffff:ffff fe80::ffff:ffff`, + }, + { + name: "math address -", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "address" "-256" | sort "+type,+address" | join "address" " " }}`, + output: `126.255.255.1 fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ff01 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff01`, + }, + { + name: "math address - underflow", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "address" "-4278190082" | sort "+type,+address" | join "address" " " }}`, + output: `127.255.255.255 fe7f:ffff:ffff:ffff:ffff:ffff:ff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ff:ffff`, + }, + { + // Note to readers: lo0's link-local address (::1) address has a mask of + // /128 which means its value never changes and this is expected. lo0's + // site-local address has a /64 address and is expected to change. + name: "math network", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "network" "+2" | sort "+type,+address" | join "address" " " }}`, + output: `127.0.0.2 ::1 fe80::2`, + }, + { + // Assume an IPv4 input of 127.0.0.1. With a value of 0xff00ff01, we wrap once on purpose. + name: "math network + wrap", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "network" "+4278255368" | sort "+type,+address" | join "address" " " }}`, + output: `127.0.255.8 ::1 fe80::ff00:ff08`, + }, + { + name: "math network -", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | math "network" "-2" | sort "+type,+address" | join "address" " " }}`, + output: `127.255.255.254 ::1 fe80::ffff:ffff:ffff:fffe`, + }, + { + // Assume an IPv4 input of 127.0.0.1. With a value of 0xff000008 it + // should wrap and underflow by 8. Assume an IPv6 input of ::1. With a + // value of -0xff000008 the value underflows and wraps. + name: "math network - underflow+wrap", + input: `{{GetAllInterfaces | include "name" "^lo0$" | include "type" "IP" | sort "+type,+address" | math "network" "-4278190088" | join "address" " " }}`, + output: `127.255.255.248 ::1 fe80::ffff:ffff:ff:fff8`, + }, + { + // Assume the private IPs available on the host are: 10.1.2.3 + // fe80::1025:f732:1001:203 + name: "GetPrivateIPs", + input: `{{GetPrivateIPs}}`, + output: `10.1.2.3 fe80::1025:f732:1001:203`, + }, + { + // Assume the public IPs available on the host are: 1.2.3.4 6.7.8.9 + name: "GetPublicIPs", + input: `{{GetPublicIPs}}`, + output: `1.2.3.4 6.7.8.9`, + }, + { + // Assume the private IPs on this host are just the IPv4 addresses: + // 10.1.2.3 and 172.16.4.6 + name: "GetInterfaceIPs", + input: `{{GetInterfaceIPs "en0"}}`, + output: `10.1.2.3 and 172.16.4.6`, + }, } for i, test := range tests { |