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 }