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