// (c) 2019-2020, Ava Labs, Inc. All rights reserved. // See the file LICENSE for licensing terms. package utils import ( "errors" "fmt" "net" "strconv" ) // This was taken from: https://stackoverflow.com/a/50825191/3478466 var privateIPBlocks []*net.IPNet func init() { for _, cidr := range []string{ "127.0.0.0/8", // IPv4 loopback "10.0.0.0/8", // RFC1918 "172.16.0.0/12", // RFC1918 "192.168.0.0/16", // RFC1918 "169.254.0.0/16", // RFC3927 link-local "::1/128", // IPv6 loopback "fe80::/10", // IPv6 link-local "fc00::/7", // IPv6 unique local addr } { _, block, err := net.ParseCIDR(cidr) if err != nil { panic(fmt.Errorf("parse error on %q: %v", cidr, err)) } privateIPBlocks = append(privateIPBlocks, block) } } var ( errBadIP = errors.New("bad ip format") ) // IPDesc ... type IPDesc struct { IP net.IP Port uint16 } // Equal ... func (ipDesc IPDesc) Equal(otherIPDesc IPDesc) bool { return ipDesc.Port == otherIPDesc.Port && ipDesc.IP.Equal(otherIPDesc.IP) } // PortString ... func (ipDesc IPDesc) PortString() string { return fmt.Sprintf(":%d", ipDesc.Port) } func (ipDesc IPDesc) String() string { return net.JoinHostPort(ipDesc.IP.String(), fmt.Sprintf("%d", ipDesc.Port)) } // IsPrivate attempts to decide if the ip address in this descriptor is a local // ip address. // This function was taken from: https://stackoverflow.com/a/50825191/3478466 func (ipDesc IPDesc) IsPrivate() bool { ip := ipDesc.IP if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() { return true } for _, block := range privateIPBlocks { if block.Contains(ip) { return true } } return true } // IsZero returns if the IP or port is zeroed out func (ipDesc IPDesc) IsZero() bool { ip := ipDesc.IP return ipDesc.Port == 0 || len(ip) == 0 || ip.Equal(net.IPv4zero) || ip.Equal(net.IPv6zero) } // ToIPDesc ... func ToIPDesc(str string) (IPDesc, error) { host, portStr, err := net.SplitHostPort(str) if err != nil { return IPDesc{}, errBadIP } port, err := strconv.ParseUint(portStr, 10 /*=base*/, 16 /*=size*/) if err != nil { // TODO: Should this return a locally defined error? (e.g. errBadPort) return IPDesc{}, err } ip := net.ParseIP(host) if ip == nil { return IPDesc{}, errBadIP } return IPDesc{ IP: ip, Port: uint16(port), }, nil }