Update `hashicorp/go-sockaddr` to account for `tun(4)` interfaces.

This commit is contained in:
Sean Chittenden 2017-01-17 12:37:56 -08:00
parent 8d57727ff0
commit c91c7f7df9
No known key found for this signature in database
GPG Key ID: 4EBC9DC16C2E5E16
16 changed files with 241 additions and 214 deletions

View File

@ -1,52 +0,0 @@
TOOLS= golang.org/x/tools/cover
GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp
GOCOVER_FILE?= .cover.out
GOCOVERHTML?= coverage.html
test:: $(GOCOVER_FILE)
@$(MAKE) -C cmd/sockaddr test
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)"
@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)
$(GOCOVERHTML): $(GOCOVER_FILE)
go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML)
coverage_report:: $(GOCOVER_FILE)
go tool cover -html=$(GOCOVER_FILE)
audit_tools::
@go get -u github.com/golang/lint/golint && echo "Installed golint:"
@go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:"
@go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:"
@go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:"
@go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:"
audit::
deadcode
go tool vet -all *.go
go tool vet -shadow=true *.go
golint *.go
ineffassign .
gocyclo -over 65 *.go
misspell *.go
clean::
rm -f $(GOCOVER_FILE) $(GOCOVERHTML)
dev::
@go build
@make -B -C cmd/sockaddr sockaddr
install::
@go 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

View File

@ -216,7 +216,12 @@ func GetAllInterfaces() (IfAddrs, error) {
// GetDefaultInterfaces returns IfAddrs of the addresses attached to the default
// route.
func GetDefaultInterfaces() (IfAddrs, error) {
defaultIfName, err := getDefaultIfName()
ri, err := NewRouteInfo()
if err != nil {
return nil, err
}
defaultIfName, err := ri.GetDefaultInterfaceName()
if err != nil {
return nil, err
}
@ -849,9 +854,9 @@ func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) {
}
if end {
return in[len(in)-off : len(in)], nil
return in[len(in)-off:], nil
}
return in[off:len(in)], nil
return in[off:], nil
}
func (ifAddr IfAddr) String() string {

View File

@ -1,30 +0,0 @@
// +build darwin dragonfly freebsd netbsd openbsd
package sockaddr
import (
"errors"
"os/exec"
)
// defaultBSDIfNameCmd is the comamnd to run on BSDs to get the default
// interface
func defaultBSDIfNameCmd() []string {
return []string{"/sbin/route", "-n", "get", "default"}
}
// getDefaultIfName is a *BSD-specific function for extracting the name of the
// interface from route(8).
func getDefaultIfName() (string, error) {
var cmd []string = defaultBSDIfNameCmd()
out, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View File

@ -1,28 +0,0 @@
package sockaddr
import (
"errors"
"os/exec"
)
// defaultLinuxIfNameCmd is the comamnd to run on Linux to get the default
// interface.
func defaultLinuxIfNameCmd() []string {
return []string{"/sbin/ip", "route"}
}
// getDefaultIfName is a Linux-specific function for extracting the name of the
// interface from ip(8).
func getDefaultIfName() (string, error) {
var cmd []string = defaultLinuxIfNameCmd()
out, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View File

@ -1,28 +0,0 @@
package sockaddr
import (
"errors"
"os/exec"
)
// defaultSolarisIfNameCmd is the comamnd to run on Solaris to get the default
// interface
func defaultSolarisIfNameCmd() []string {
return []string{"/usr/sbin/route", "-n", "get", "default"}
}
// getDefaultIfName is an Solaris-specific function for extracting the name of
// the interface from route(8).
func getDefaultIfName() (string, error) {
var cmd []string = defaultSolarisIfNameCmd()
out, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View File

@ -1,38 +0,0 @@
package sockaddr
import "os/exec"
// defaultWindowsIfNameCmd is the comamnd to run on Windows to get the default
// interface.
func defaultWindowsIfNameCmd() []string {
return []string{"netstat", "-rn"}
}
// defaultWindowsIfNameCmd is the comamnd to run on Windows to get the default
// interface.
func defaultWindowsIPConfigCmd() []string {
return []string{"ipconfig"}
}
// getDefaultIfName is a Windows-specific function for extracting the name of
// the interface from `netstat -rn` and `ipconfig`.
func getDefaultIfName() (string, error) {
var cmd []string = defaultWindowsIfNameCmd()
ifNameOut, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
cmd = defaultWindowsIPConfigCmd()
ipconfigOut, err := exec.Command(cmd[0], cmd[1:]...).Output()
if err != nil {
return "", err
}
ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
if err != nil {
return "", err
}
return ifName, nil
}

View File

@ -2,6 +2,7 @@ package sockaddr
import (
"fmt"
"math/big"
"net"
"strings"
)
@ -131,10 +132,27 @@ func ipAddrInit() {
return fmt.Sprintf("%d", ip.Maskbits())
},
"netmask": func(ip IPAddr) string {
return ip.NetIPMask().String()
switch v := ip.(type) {
case IPv4Addr:
ipv4Mask := IPv4Addr{
Address: IPv4Address(v.Mask),
Mask: IPv4HostMask,
}
return ipv4Mask.String()
case IPv6Addr:
ipv6Mask := new(big.Int)
ipv6Mask.Set(v.Mask)
ipv6MaskAddr := IPv6Addr{
Address: IPv6Address(ipv6Mask),
Mask: ipv6HostMask,
}
return ipv6MaskAddr.String()
default:
return fmt.Sprintf("<unsupported type: %T>", ip)
}
},
"network": func(ip IPAddr) string {
return ip.Network().String()
return ip.Network().NetIP().String()
},
"octets": func(ip IPAddr) string {
octets := ip.Octets()

View File

@ -4,6 +4,7 @@ import (
"encoding/binary"
"fmt"
"net"
"regexp"
"strconv"
"strings"
)
@ -26,6 +27,7 @@ const IPv4HostMask = IPv4Mask(0xffffffff)
// ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes.
var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string
var ipv4AddrAttrs []AttrName
var trailingHexNetmaskRE *regexp.Regexp
// IPv4Addr implements a convenience wrapper around the union of Go's
// built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements
@ -40,6 +42,7 @@ type IPv4Addr struct {
func init() {
ipv4AddrInit()
trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`)
}
// NewIPv4Addr creates an IPv4Addr from a string. String can be in the form
@ -52,6 +55,13 @@ func init() {
// To create uint32 values from net.IP, always test to make sure the address
// returned can be converted to a 4 byte array using To4().
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 {
ipv4Str = ipv4Str[:match[0]]
}
// Parse as an IPv4 CIDR
ipAddr, network, err := net.ParseCIDR(ipv4Str)
if err == nil {

View File

@ -38,31 +38,31 @@ func KnownRFCs() map[uint]SockAddrs {
// NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a
// RADIX tree, but `ENOTIME`. Patches welcome.
return map[uint]SockAddrs{
919: SockAddrs{
919: {
// [RFC919] Broadcasting Internet Datagrams
MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards
},
1122: SockAddrs{
1122: {
// [RFC1122] Requirements for Internet Hosts -- Communication Layers
MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3
MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3
},
1112: SockAddrs{
1112: {
// [RFC1112] Host Extensions for IP Multicasting
MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses
},
1918: SockAddrs{
1918: {
// [RFC1918] Address Allocation for Private Internets
MustIPv4Addr("10.0.0.0/8"),
MustIPv4Addr("172.16.0.0/12"),
MustIPv4Addr("192.168.0.0/16"),
},
2544: SockAddrs{
2544: {
// [RFC2544] Benchmarking Methodology for Network
// Interconnect Devices
MustIPv4Addr("198.18.0.0/15"),
},
2765: SockAddrs{
2765: {
// [RFC2765] Stateless IP/ICMP Translation Algorithm
// (SIIT) (obsoleted by RFCs 6145, which itself was
// later obsoleted by 7915).
@ -70,7 +70,7 @@ func KnownRFCs() map[uint]SockAddrs {
// [RFC2765], §2.1 Addresses
MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"),
},
2928: SockAddrs{
2928: {
// [RFC2928] Initial IPv6 Sub-TLA ID Assignments
MustIPv6Addr("2001::/16"), // Superblock
//MustIPv6Addr("2001:0000::/23"), // IANA
@ -81,13 +81,13 @@ func KnownRFCs() map[uint]SockAddrs {
// ...
//MustIPv6Addr("2001:FE00::/23"), // (future assignment)
},
3056: SockAddrs{ // 6to4 address
3056: { // 6to4 address
// [RFC3056] Connection of IPv6 Domains via IPv4 Clouds
// [RFC3056], §2 IPv6 Prefix Allocation
MustIPv6Addr("2002::/16"),
},
3068: SockAddrs{
3068: {
// [RFC3068] An Anycast Prefix for 6to4 Relay Routers
// (obsolete by RFC7526)
@ -99,11 +99,11 @@ func KnownRFCs() map[uint]SockAddrs {
// NOTE: /120 == 128-(32-24)
MustIPv6Addr("2002:c058:6301::/120"),
},
3171: SockAddrs{
3171: {
// [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments
MustIPv4Addr("224.0.0.0/4"),
},
3330: SockAddrs{
3330: {
// [RFC3330] Special-Use IPv4 Addresses
// Addresses in this block refer to source hosts on
@ -237,25 +237,25 @@ func KnownRFCs() map[uint]SockAddrs {
// for future use. [RFC1700, page 4]
MustIPv4Addr("240.0.0.0/4"),
},
3849: SockAddrs{
3849: {
// [RFC3849] IPv6 Address Prefix Reserved for Documentation
MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations
},
3927: SockAddrs{
3927: {
// [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses
MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection
},
4038: SockAddrs{
4038: {
// [RFC4038] Application Aspects of IPv6 Transition
// [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node
MustIPv6Addr("0:0:0:0:0:ffff::/96"),
},
4193: SockAddrs{
4193: {
// [RFC4193] Unique Local IPv6 Unicast Addresses
MustIPv6Addr("fc00::/7"),
},
4291: SockAddrs{
4291: {
// [RFC4291] IP Version 6 Addressing Architecture
// [RFC4291], §2.5.2 The Unspecified Address
@ -314,55 +314,55 @@ func KnownRFCs() map[uint]SockAddrs {
// * ff02::1:ff00:0/104 // Solicited-node multicast address.
// * ff02::2:ff00:0/104 // Node Information Queries
},
4380: SockAddrs{
4380: {
// [RFC4380] Teredo: Tunneling IPv6 over UDP through
// Network Address Translations (NATs)
// [RFC4380], §2.6 Global Teredo IPv6 Service Prefix
MustIPv6Addr("2001:0000::/32"),
},
4773: SockAddrs{
4773: {
// [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block
MustIPv6Addr("2001:0000::/23"), // IANA
},
4843: SockAddrs{
4843: {
// [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID)
MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations
},
5180: SockAddrs{
5180: {
// [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices
MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations
},
5735: SockAddrs{
5735: {
// [RFC5735] Special Use IPv4 Addresses
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
MustIPv4Addr("198.18.0.0/15"), // Benchmarks
},
5737: SockAddrs{
5737: {
// [RFC5737] IPv4 Address Blocks Reserved for Documentation
MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1
MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2
MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3
},
6052: SockAddrs{
6052: {
// [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators
MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix
},
6333: SockAddrs{
6333: {
// [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion
MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address
},
6598: SockAddrs{
6598: {
// [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space
MustIPv4Addr("100.64.0.0/10"),
},
6666: SockAddrs{
6666: {
// [RFC6666] A Discard Prefix for IPv6
MustIPv6Addr("0100::/64"),
},
6890: SockAddrs{
6890: {
// [RFC6890] Special-Purpose IP Address Registries
// From "RFC6890 §2.2.1 Information Requirements":
@ -894,11 +894,11 @@ func KnownRFCs() map[uint]SockAddrs {
+----------------------+-----------------------+*/
MustIPv6Addr("fe80::/10"),
},
7335: SockAddrs{
7335: {
// [RFC7335] IPv4 Service Continuity Prefix
MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations
},
ForwardingBlacklist: SockAddrs{ // Pseudo-RFC
ForwardingBlacklist: { // Pseudo-RFC
// Blacklist of non-forwardable IP blocks taken from RFC6890
//
// TODO: the attributes for forwardable should be
@ -936,7 +936,7 @@ func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) {
// Blacklist of faux-RFCs. Don't show the world that we're abusing the
// RFC system in this library.
rfcBlacklist := map[uint]struct{}{
ForwardingBlacklist: struct{}{},
ForwardingBlacklist: {},
}
for rfcNum, sas := range rfcNetMap {

19
vendor/github.com/hashicorp/go-sockaddr/route_info.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
package sockaddr
// RouteInterface specifies an interface for obtaining memoized route table and
// network information from a given OS.
type RouteInterface interface {
// GetDefaultInterfaceName returns the name of the interface that has a
// default route or an error and an empty string if a problem was
// encountered.
GetDefaultInterfaceName() (string, error)
}
// VisitCommands visits each command used by the platform-specific RouteInfo
// implementation.
func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) {
for k, v := range ri.cmds {
cmds := append([]string(nil), v...)
fn(k, cmds)
}
}

View File

@ -0,0 +1,36 @@
// +build darwin dragonfly freebsd netbsd openbsd
package sockaddr
import "os/exec"
var cmds map[string][]string = map[string][]string{
"route": {"/sbin/route", "-n", "get", "default"},
}
type routeInfo struct {
cmds map[string][]string
}
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
// interface.
func NewRouteInfo() (routeInfo, error) {
return routeInfo{
cmds: cmds,
}, nil
}
// GetDefaultInterfaceName returns the interace name attached to the default
// route on the default interface.
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
return "", err
}
return ifName, nil
}

View File

@ -0,0 +1,37 @@
package sockaddr
import (
"errors"
"os/exec"
)
var cmds map[string][]string = map[string][]string{
"ip": {"/sbin/ip", "route"},
}
type routeInfo struct {
cmds map[string][]string
}
// NewRouteInfo returns a Linux-specific implementation of the RouteInfo
// interface.
func NewRouteInfo() (routeInfo, error) {
return routeInfo{
cmds: cmds,
}, nil
}
// GetDefaultInterfaceName returns the interace name attached to the default
// route on the default interface.
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
out, err := exec.Command(cmds["ip"][0], cmds["ip"][1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View File

@ -0,0 +1,37 @@
package sockaddr
import (
"errors"
"os/exec"
)
var cmds map[string][]string = map[string][]string{
"route": {"/usr/sbin/route", "-n", "get", "default"},
}
type routeInfo struct {
cmds map[string][]string
}
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
// interface.
func NewRouteInfo() (routeInfo, error) {
return routeInfo{
cmds: cmds,
}, nil
}
// GetDefaultInterfaceName returns the interace name attached to the default
// route on the default interface.
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output()
if err != nil {
return "", err
}
var ifName string
if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil {
return "", errors.New("No default interface found")
}
return ifName, nil
}

View File

@ -0,0 +1,41 @@
package sockaddr
import "os/exec"
var cmds map[string][]string = map[string][]string{
"netstat": {"netstat", "-rn"},
"ipconfig": {"ipconfig"},
}
type routeInfo struct {
cmds map[string][]string
}
// NewRouteInfo returns a BSD-specific implementation of the RouteInfo
// interface.
func NewRouteInfo() (routeInfo, error) {
return routeInfo{
cmds: cmds,
}, nil
}
// GetDefaultInterfaceName returns the interace name attached to the default
// route on the default interface.
func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output()
if err != nil {
return "", err
}
ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output()
if err != nil {
return "", err
}
ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut))
if err != nil {
return "", err
}
return ifName, nil
}

6
vendor/vendor.json vendored
View File

@ -456,10 +456,10 @@
"revisionTime": "2016-09-30T03:51:02Z"
},
{
"checksumSHA1": "gnhc8egaCa7Ue516rnQkfutdBO8=",
"checksumSHA1": "L9iVjsIjeU9Ia1VZUY417ZHBAtc=",
"path": "github.com/hashicorp/go-sockaddr",
"revision": "af174a6fe6c9f9a049a638e1dae7bc4442c4d426",
"revisionTime": "2016-12-02T14:18:37Z"
"revision": "945b922c7db81f071a1f176e747e9857b76ed7c3",
"revisionTime": "2017-01-17T20:27:00Z"
},
{
"checksumSHA1": "lPzwetgfMBtpHqdTPolgejMctVQ=",