github.com/devwanda/aphelion-staking@v0.33.9/p2p/netaddress.go (about)

     1  // Modified for Tendermint
     2  // Originally Copyright (c) 2013-2014 Conformal Systems LLC.
     3  // https://github.com/conformal/btcd/blob/master/LICENSE
     4  
     5  package p2p
     6  
     7  import (
     8  	"encoding/hex"
     9  	"flag"
    10  	"fmt"
    11  	"net"
    12  	"strconv"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // NetAddress defines information about a peer on the network
    20  // including its ID, IP address, and port.
    21  type NetAddress struct {
    22  	ID   ID     `json:"id"`
    23  	IP   net.IP `json:"ip"`
    24  	Port uint16 `json:"port"`
    25  
    26  	// TODO:
    27  	// Name string `json:"name"` // optional DNS name
    28  
    29  	// memoize .String()
    30  	str string
    31  }
    32  
    33  // IDAddressString returns id@hostPort. It strips the leading
    34  // protocol from protocolHostPort if it exists.
    35  func IDAddressString(id ID, protocolHostPort string) string {
    36  	hostPort := removeProtocolIfDefined(protocolHostPort)
    37  	return fmt.Sprintf("%s@%s", id, hostPort)
    38  }
    39  
    40  // NewNetAddress returns a new NetAddress using the provided TCP
    41  // address. When testing, other net.Addr (except TCP) will result in
    42  // using 0.0.0.0:0. When normal run, other net.Addr (except TCP) will
    43  // panic. Panics if ID is invalid.
    44  // TODO: socks proxies?
    45  func NewNetAddress(id ID, addr net.Addr) *NetAddress {
    46  	tcpAddr, ok := addr.(*net.TCPAddr)
    47  	if !ok {
    48  		if flag.Lookup("test.v") == nil { // normal run
    49  			panic(fmt.Sprintf("Only TCPAddrs are supported. Got: %v", addr))
    50  		} else { // in testing
    51  			netAddr := NewNetAddressIPPort(net.IP("127.0.0.1"), 0)
    52  			netAddr.ID = id
    53  			return netAddr
    54  		}
    55  	}
    56  
    57  	if err := validateID(id); err != nil {
    58  		panic(fmt.Sprintf("Invalid ID %v: %v (addr: %v)", id, err, addr))
    59  	}
    60  
    61  	ip := tcpAddr.IP
    62  	port := uint16(tcpAddr.Port)
    63  	na := NewNetAddressIPPort(ip, port)
    64  	na.ID = id
    65  	return na
    66  }
    67  
    68  // NewNetAddressString returns a new NetAddress using the provided address in
    69  // the form of "ID@IP:Port".
    70  // Also resolves the host if host is not an IP.
    71  // Errors are of type ErrNetAddressXxx where Xxx is in (NoID, Invalid, Lookup)
    72  func NewNetAddressString(addr string) (*NetAddress, error) {
    73  	addrWithoutProtocol := removeProtocolIfDefined(addr)
    74  	spl := strings.Split(addrWithoutProtocol, "@")
    75  	if len(spl) != 2 {
    76  		return nil, ErrNetAddressNoID{addr}
    77  	}
    78  
    79  	// get ID
    80  	if err := validateID(ID(spl[0])); err != nil {
    81  		return nil, ErrNetAddressInvalid{addrWithoutProtocol, err}
    82  	}
    83  	var id ID
    84  	id, addrWithoutProtocol = ID(spl[0]), spl[1]
    85  
    86  	// get host and port
    87  	host, portStr, err := net.SplitHostPort(addrWithoutProtocol)
    88  	if err != nil {
    89  		return nil, ErrNetAddressInvalid{addrWithoutProtocol, err}
    90  	}
    91  	if len(host) == 0 {
    92  		return nil, ErrNetAddressInvalid{
    93  			addrWithoutProtocol,
    94  			errors.New("host is empty")}
    95  	}
    96  
    97  	ip := net.ParseIP(host)
    98  	if ip == nil {
    99  		ips, err := net.LookupIP(host)
   100  		if err != nil {
   101  			return nil, ErrNetAddressLookup{host, err}
   102  		}
   103  		ip = ips[0]
   104  	}
   105  
   106  	port, err := strconv.ParseUint(portStr, 10, 16)
   107  	if err != nil {
   108  		return nil, ErrNetAddressInvalid{portStr, err}
   109  	}
   110  
   111  	na := NewNetAddressIPPort(ip, uint16(port))
   112  	na.ID = id
   113  	return na, nil
   114  }
   115  
   116  // NewNetAddressStrings returns an array of NetAddress'es build using
   117  // the provided strings.
   118  func NewNetAddressStrings(addrs []string) ([]*NetAddress, []error) {
   119  	netAddrs := make([]*NetAddress, 0)
   120  	errs := make([]error, 0)
   121  	for _, addr := range addrs {
   122  		netAddr, err := NewNetAddressString(addr)
   123  		if err != nil {
   124  			errs = append(errs, err)
   125  		} else {
   126  			netAddrs = append(netAddrs, netAddr)
   127  		}
   128  	}
   129  	return netAddrs, errs
   130  }
   131  
   132  // NewNetAddressIPPort returns a new NetAddress using the provided IP
   133  // and port number.
   134  func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress {
   135  	return &NetAddress{
   136  		IP:   ip,
   137  		Port: port,
   138  	}
   139  }
   140  
   141  // Equals reports whether na and other are the same addresses,
   142  // including their ID, IP, and Port.
   143  func (na *NetAddress) Equals(other interface{}) bool {
   144  	if o, ok := other.(*NetAddress); ok {
   145  		return na.String() == o.String()
   146  	}
   147  	return false
   148  }
   149  
   150  // Same returns true is na has the same non-empty ID or DialString as other.
   151  func (na *NetAddress) Same(other interface{}) bool {
   152  	if o, ok := other.(*NetAddress); ok {
   153  		if na.DialString() == o.DialString() {
   154  			return true
   155  		}
   156  		if na.ID != "" && na.ID == o.ID {
   157  			return true
   158  		}
   159  	}
   160  	return false
   161  }
   162  
   163  // String representation: <ID>@<IP>:<PORT>
   164  func (na *NetAddress) String() string {
   165  	if na == nil {
   166  		return "<nil-NetAddress>"
   167  	}
   168  	if na.str == "" {
   169  		addrStr := na.DialString()
   170  		if na.ID != "" {
   171  			addrStr = IDAddressString(na.ID, addrStr)
   172  		}
   173  		na.str = addrStr
   174  	}
   175  	return na.str
   176  }
   177  
   178  func (na *NetAddress) DialString() string {
   179  	if na == nil {
   180  		return "<nil-NetAddress>"
   181  	}
   182  	return net.JoinHostPort(
   183  		na.IP.String(),
   184  		strconv.FormatUint(uint64(na.Port), 10),
   185  	)
   186  }
   187  
   188  // Dial calls net.Dial on the address.
   189  func (na *NetAddress) Dial() (net.Conn, error) {
   190  	conn, err := net.Dial("tcp", na.DialString())
   191  	if err != nil {
   192  		return nil, err
   193  	}
   194  	return conn, nil
   195  }
   196  
   197  // DialTimeout calls net.DialTimeout on the address.
   198  func (na *NetAddress) DialTimeout(timeout time.Duration) (net.Conn, error) {
   199  	conn, err := net.DialTimeout("tcp", na.DialString(), timeout)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	return conn, nil
   204  }
   205  
   206  // Routable returns true if the address is routable.
   207  func (na *NetAddress) Routable() bool {
   208  	if err := na.Valid(); err != nil {
   209  		return false
   210  	}
   211  	// TODO(oga) bitcoind doesn't include RFC3849 here, but should we?
   212  	return !(na.RFC1918() || na.RFC3927() || na.RFC4862() ||
   213  		na.RFC4193() || na.RFC4843() || na.Local())
   214  }
   215  
   216  // For IPv4 these are either a 0 or all bits set address. For IPv6 a zero
   217  // address or one that matches the RFC3849 documentation address format.
   218  func (na *NetAddress) Valid() error {
   219  	if err := validateID(na.ID); err != nil {
   220  		return errors.Wrap(err, "invalid ID")
   221  	}
   222  
   223  	if na.IP == nil {
   224  		return errors.New("no IP")
   225  	}
   226  	if na.IP.IsUnspecified() || na.RFC3849() || na.IP.Equal(net.IPv4bcast) {
   227  		return errors.New("invalid IP")
   228  	}
   229  	return nil
   230  }
   231  
   232  // HasID returns true if the address has an ID.
   233  // NOTE: It does not check whether the ID is valid or not.
   234  func (na *NetAddress) HasID() bool {
   235  	return string(na.ID) != ""
   236  }
   237  
   238  // Local returns true if it is a local address.
   239  func (na *NetAddress) Local() bool {
   240  	return na.IP.IsLoopback() || zero4.Contains(na.IP)
   241  }
   242  
   243  // ReachabilityTo checks whenever o can be reached from na.
   244  func (na *NetAddress) ReachabilityTo(o *NetAddress) int {
   245  	const (
   246  		Unreachable = 0
   247  		Default     = iota
   248  		Teredo
   249  		Ipv6Weak
   250  		Ipv4
   251  		Ipv6Strong
   252  	)
   253  	switch {
   254  	case !na.Routable():
   255  		return Unreachable
   256  	case na.RFC4380():
   257  		switch {
   258  		case !o.Routable():
   259  			return Default
   260  		case o.RFC4380():
   261  			return Teredo
   262  		case o.IP.To4() != nil:
   263  			return Ipv4
   264  		default: // ipv6
   265  			return Ipv6Weak
   266  		}
   267  	case na.IP.To4() != nil:
   268  		if o.Routable() && o.IP.To4() != nil {
   269  			return Ipv4
   270  		}
   271  		return Default
   272  	default: /* ipv6 */
   273  		var tunnelled bool
   274  		// Is our v6 is tunnelled?
   275  		if o.RFC3964() || o.RFC6052() || o.RFC6145() {
   276  			tunnelled = true
   277  		}
   278  		switch {
   279  		case !o.Routable():
   280  			return Default
   281  		case o.RFC4380():
   282  			return Teredo
   283  		case o.IP.To4() != nil:
   284  			return Ipv4
   285  		case tunnelled:
   286  			// only prioritise ipv6 if we aren't tunnelling it.
   287  			return Ipv6Weak
   288  		}
   289  		return Ipv6Strong
   290  	}
   291  }
   292  
   293  // RFC1918: IPv4 Private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
   294  // RFC3849: IPv6 Documentation address  (2001:0DB8::/32)
   295  // RFC3927: IPv4 Autoconfig (169.254.0.0/16)
   296  // RFC3964: IPv6 6to4 (2002::/16)
   297  // RFC4193: IPv6 unique local (FC00::/7)
   298  // RFC4380: IPv6 Teredo tunneling (2001::/32)
   299  // RFC4843: IPv6 ORCHID: (2001:10::/28)
   300  // RFC4862: IPv6 Autoconfig (FE80::/64)
   301  // RFC6052: IPv6 well known prefix (64:FF9B::/96)
   302  // RFC6145: IPv6 IPv4 translated address ::FFFF:0:0:0/96
   303  var rfc1918_10 = net.IPNet{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(8, 32)}
   304  var rfc1918_192 = net.IPNet{IP: net.ParseIP("192.168.0.0"), Mask: net.CIDRMask(16, 32)}
   305  var rfc1918_172 = net.IPNet{IP: net.ParseIP("172.16.0.0"), Mask: net.CIDRMask(12, 32)}
   306  var rfc3849 = net.IPNet{IP: net.ParseIP("2001:0DB8::"), Mask: net.CIDRMask(32, 128)}
   307  var rfc3927 = net.IPNet{IP: net.ParseIP("169.254.0.0"), Mask: net.CIDRMask(16, 32)}
   308  var rfc3964 = net.IPNet{IP: net.ParseIP("2002::"), Mask: net.CIDRMask(16, 128)}
   309  var rfc4193 = net.IPNet{IP: net.ParseIP("FC00::"), Mask: net.CIDRMask(7, 128)}
   310  var rfc4380 = net.IPNet{IP: net.ParseIP("2001::"), Mask: net.CIDRMask(32, 128)}
   311  var rfc4843 = net.IPNet{IP: net.ParseIP("2001:10::"), Mask: net.CIDRMask(28, 128)}
   312  var rfc4862 = net.IPNet{IP: net.ParseIP("FE80::"), Mask: net.CIDRMask(64, 128)}
   313  var rfc6052 = net.IPNet{IP: net.ParseIP("64:FF9B::"), Mask: net.CIDRMask(96, 128)}
   314  var rfc6145 = net.IPNet{IP: net.ParseIP("::FFFF:0:0:0"), Mask: net.CIDRMask(96, 128)}
   315  var zero4 = net.IPNet{IP: net.ParseIP("0.0.0.0"), Mask: net.CIDRMask(8, 32)}
   316  var (
   317  	// onionCatNet defines the IPv6 address block used to support Tor.
   318  	// bitcoind encodes a .onion address as a 16 byte number by decoding the
   319  	// address prior to the .onion (i.e. the key hash) base32 into a ten
   320  	// byte number. It then stores the first 6 bytes of the address as
   321  	// 0xfd, 0x87, 0xd8, 0x7e, 0xeb, 0x43.
   322  	//
   323  	// This is the same range used by OnionCat, which is part part of the
   324  	// RFC4193 unique local IPv6 range.
   325  	//
   326  	// In summary the format is:
   327  	// { magic 6 bytes, 10 bytes base32 decode of key hash }
   328  	onionCatNet = ipNet("fd87:d87e:eb43::", 48, 128)
   329  )
   330  
   331  // ipNet returns a net.IPNet struct given the passed IP address string, number
   332  // of one bits to include at the start of the mask, and the total number of bits
   333  // for the mask.
   334  func ipNet(ip string, ones, bits int) net.IPNet {
   335  	return net.IPNet{IP: net.ParseIP(ip), Mask: net.CIDRMask(ones, bits)}
   336  }
   337  
   338  func (na *NetAddress) RFC1918() bool {
   339  	return rfc1918_10.Contains(na.IP) ||
   340  		rfc1918_192.Contains(na.IP) ||
   341  		rfc1918_172.Contains(na.IP)
   342  }
   343  func (na *NetAddress) RFC3849() bool     { return rfc3849.Contains(na.IP) }
   344  func (na *NetAddress) RFC3927() bool     { return rfc3927.Contains(na.IP) }
   345  func (na *NetAddress) RFC3964() bool     { return rfc3964.Contains(na.IP) }
   346  func (na *NetAddress) RFC4193() bool     { return rfc4193.Contains(na.IP) }
   347  func (na *NetAddress) RFC4380() bool     { return rfc4380.Contains(na.IP) }
   348  func (na *NetAddress) RFC4843() bool     { return rfc4843.Contains(na.IP) }
   349  func (na *NetAddress) RFC4862() bool     { return rfc4862.Contains(na.IP) }
   350  func (na *NetAddress) RFC6052() bool     { return rfc6052.Contains(na.IP) }
   351  func (na *NetAddress) RFC6145() bool     { return rfc6145.Contains(na.IP) }
   352  func (na *NetAddress) OnionCatTor() bool { return onionCatNet.Contains(na.IP) }
   353  
   354  func removeProtocolIfDefined(addr string) string {
   355  	if strings.Contains(addr, "://") {
   356  		return strings.Split(addr, "://")[1]
   357  	}
   358  	return addr
   359  
   360  }
   361  
   362  func validateID(id ID) error {
   363  	if len(id) == 0 {
   364  		return errors.New("no ID")
   365  	}
   366  	idBytes, err := hex.DecodeString(string(id))
   367  	if err != nil {
   368  		return err
   369  	}
   370  	if len(idBytes) != IDByteLength {
   371  		return fmt.Errorf("invalid hex length - got %d, expected %d", len(idBytes), IDByteLength)
   372  	}
   373  	return nil
   374  }