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