github.com/ethereum/go-ethereum@v1.16.1/p2p/enode/node.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package enode 18 19 import ( 20 "crypto/ecdsa" 21 "encoding/base64" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "math/bits" 26 "net" 27 "net/netip" 28 "strings" 29 30 "github.com/ethereum/go-ethereum/p2p/enr" 31 "github.com/ethereum/go-ethereum/rlp" 32 ) 33 34 var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record") 35 36 // Node represents a host on the network. 37 type Node struct { 38 r enr.Record 39 id ID 40 41 // hostname tracks the DNS name of the node. 42 hostname string 43 44 // endpoint information 45 ip netip.Addr 46 udp uint16 47 tcp uint16 48 } 49 50 // New wraps a node record. The record must be valid according to the given 51 // identity scheme. 52 func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) { 53 if err := r.VerifySignature(validSchemes); err != nil { 54 return nil, err 55 } 56 var id ID 57 if n := copy(id[:], validSchemes.NodeAddr(r)); n != len(id) { 58 return nil, fmt.Errorf("invalid node ID length %d, need %d", n, len(id)) 59 } 60 return newNodeWithID(r, id), nil 61 } 62 63 func newNodeWithID(r *enr.Record, id ID) *Node { 64 n := &Node{r: *r, id: id} 65 // Set the preferred endpoint. 66 // Here we decide between IPv4 and IPv6, choosing the 'most global' address. 67 var ip4 netip.Addr 68 var ip6 netip.Addr 69 n.Load((*enr.IPv4Addr)(&ip4)) 70 n.Load((*enr.IPv6Addr)(&ip6)) 71 valid4 := validIP(ip4) 72 valid6 := validIP(ip6) 73 switch { 74 case valid4 && valid6: 75 if localityScore(ip4) >= localityScore(ip6) { 76 n.setIP4(ip4) 77 } else { 78 n.setIP6(ip6) 79 } 80 case valid4: 81 n.setIP4(ip4) 82 case valid6: 83 n.setIP6(ip6) 84 default: 85 n.setIPv4Ports() 86 } 87 return n 88 } 89 90 // validIP reports whether 'ip' is a valid node endpoint IP address. 91 func validIP(ip netip.Addr) bool { 92 return ip.IsValid() && !ip.IsMulticast() 93 } 94 95 func localityScore(ip netip.Addr) int { 96 switch { 97 case ip.IsUnspecified(): 98 return 0 99 case ip.IsLoopback(): 100 return 1 101 case ip.IsLinkLocalUnicast(): 102 return 2 103 case ip.IsPrivate(): 104 return 3 105 default: 106 return 4 107 } 108 } 109 110 func (n *Node) setIP4(ip netip.Addr) { 111 n.ip = ip 112 n.setIPv4Ports() 113 } 114 115 func (n *Node) setIPv4Ports() { 116 n.Load((*enr.UDP)(&n.udp)) 117 n.Load((*enr.TCP)(&n.tcp)) 118 } 119 120 func (n *Node) setIP6(ip netip.Addr) { 121 if ip.Is4In6() { 122 n.setIP4(ip) 123 return 124 } 125 n.ip = ip 126 if err := n.Load((*enr.UDP6)(&n.udp)); err != nil { 127 n.Load((*enr.UDP)(&n.udp)) 128 } 129 if err := n.Load((*enr.TCP6)(&n.tcp)); err != nil { 130 n.Load((*enr.TCP)(&n.tcp)) 131 } 132 } 133 134 // MustParse parses a node record or enode:// URL. It panics if the input is invalid. 135 func MustParse(rawurl string) *Node { 136 n, err := Parse(ValidSchemes, rawurl) 137 if err != nil { 138 panic("invalid node: " + err.Error()) 139 } 140 return n 141 } 142 143 // Parse decodes and verifies a base64-encoded node record. 144 func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) { 145 if strings.HasPrefix(input, "enode://") { 146 return ParseV4(input) 147 } 148 if !strings.HasPrefix(input, "enr:") { 149 return nil, errMissingPrefix 150 } 151 bin, err := base64.RawURLEncoding.DecodeString(input[4:]) 152 if err != nil { 153 return nil, err 154 } 155 var r enr.Record 156 if err := rlp.DecodeBytes(bin, &r); err != nil { 157 return nil, err 158 } 159 return New(validSchemes, &r) 160 } 161 162 // ID returns the node identifier. 163 func (n *Node) ID() ID { 164 return n.id 165 } 166 167 // Seq returns the sequence number of the underlying record. 168 func (n *Node) Seq() uint64 { 169 return n.r.Seq() 170 } 171 172 // Load retrieves an entry from the underlying record. 173 func (n *Node) Load(k enr.Entry) error { 174 return n.r.Load(k) 175 } 176 177 // IP returns the IP address of the node. 178 func (n *Node) IP() net.IP { 179 return net.IP(n.ip.AsSlice()) 180 } 181 182 // IPAddr returns the IP address of the node. 183 func (n *Node) IPAddr() netip.Addr { 184 return n.ip 185 } 186 187 // UDP returns the UDP port of the node. 188 func (n *Node) UDP() int { 189 return int(n.udp) 190 } 191 192 // TCP returns the TCP port of the node. 193 func (n *Node) TCP() int { 194 return int(n.tcp) 195 } 196 197 // WithHostname adds a DNS hostname to the node. 198 func (n *Node) WithHostname(hostname string) *Node { 199 cpy := *n 200 cpy.hostname = hostname 201 return &cpy 202 } 203 204 // Hostname returns the DNS name assigned by WithHostname. 205 func (n *Node) Hostname() string { 206 return n.hostname 207 } 208 209 // UDPEndpoint returns the announced UDP endpoint. 210 func (n *Node) UDPEndpoint() (netip.AddrPort, bool) { 211 if !n.ip.IsValid() || n.ip.IsUnspecified() || n.udp == 0 { 212 return netip.AddrPort{}, false 213 } 214 return netip.AddrPortFrom(n.ip, n.udp), true 215 } 216 217 // TCPEndpoint returns the announced TCP endpoint. 218 func (n *Node) TCPEndpoint() (netip.AddrPort, bool) { 219 if !n.ip.IsValid() || n.ip.IsUnspecified() || n.tcp == 0 { 220 return netip.AddrPort{}, false 221 } 222 return netip.AddrPortFrom(n.ip, n.tcp), true 223 } 224 225 // QUICEndpoint returns the announced QUIC endpoint. 226 func (n *Node) QUICEndpoint() (netip.AddrPort, bool) { 227 var quic uint16 228 if n.ip.Is4() || n.ip.Is4In6() { 229 n.Load((*enr.QUIC)(&quic)) 230 } else if n.ip.Is6() { 231 n.Load((*enr.QUIC6)(&quic)) 232 } 233 if !n.ip.IsValid() || n.ip.IsUnspecified() || quic == 0 { 234 return netip.AddrPort{}, false 235 } 236 return netip.AddrPortFrom(n.ip, quic), true 237 } 238 239 // Pubkey returns the secp256k1 public key of the node, if present. 240 func (n *Node) Pubkey() *ecdsa.PublicKey { 241 var key ecdsa.PublicKey 242 if n.Load((*Secp256k1)(&key)) != nil { 243 return nil 244 } 245 return &key 246 } 247 248 // Record returns the node's record. The return value is a copy and may 249 // be modified by the caller. 250 func (n *Node) Record() *enr.Record { 251 cpy := n.r 252 return &cpy 253 } 254 255 // ValidateComplete checks whether n has a valid IP and UDP port. 256 // Deprecated: don't use this method. 257 func (n *Node) ValidateComplete() error { 258 if !n.ip.IsValid() { 259 return errors.New("missing IP address") 260 } 261 if n.ip.IsMulticast() || n.ip.IsUnspecified() { 262 return errors.New("invalid IP (multicast/unspecified)") 263 } 264 if n.udp == 0 { 265 return errors.New("missing UDP port") 266 } 267 // Validate the node key (on curve, etc.). 268 var key Secp256k1 269 return n.Load(&key) 270 } 271 272 // String returns the text representation of the record. 273 func (n *Node) String() string { 274 if isNewV4(n) { 275 return n.URLv4() // backwards-compatibility glue for NewV4 nodes 276 } 277 enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid 278 b64 := base64.RawURLEncoding.EncodeToString(enc) 279 return "enr:" + b64 280 } 281 282 // MarshalText implements encoding.TextMarshaler. 283 func (n *Node) MarshalText() ([]byte, error) { 284 return []byte(n.String()), nil 285 } 286 287 // UnmarshalText implements encoding.TextUnmarshaler. 288 func (n *Node) UnmarshalText(text []byte) error { 289 dec, err := Parse(ValidSchemes, string(text)) 290 if err == nil { 291 *n = *dec 292 } 293 return err 294 } 295 296 // ID is a unique identifier for each node. 297 type ID [32]byte 298 299 // Bytes returns a byte slice representation of the ID 300 func (n ID) Bytes() []byte { 301 return n[:] 302 } 303 304 // ID prints as a long hexadecimal number. 305 func (n ID) String() string { 306 return fmt.Sprintf("%x", n[:]) 307 } 308 309 // GoString returns the Go syntax representation of a ID is a call to HexID. 310 func (n ID) GoString() string { 311 return fmt.Sprintf("enode.HexID(\"%x\")", n[:]) 312 } 313 314 // TerminalString returns a shortened hex string for terminal logging. 315 func (n ID) TerminalString() string { 316 return hex.EncodeToString(n[:8]) 317 } 318 319 // MarshalText implements the encoding.TextMarshaler interface. 320 func (n ID) MarshalText() ([]byte, error) { 321 return []byte(hex.EncodeToString(n[:])), nil 322 } 323 324 // UnmarshalText implements the encoding.TextUnmarshaler interface. 325 func (n *ID) UnmarshalText(text []byte) error { 326 id, err := ParseID(string(text)) 327 if err != nil { 328 return err 329 } 330 *n = id 331 return nil 332 } 333 334 // HexID converts a hex string to an ID. 335 // The string may be prefixed with 0x. 336 // It panics if the string is not a valid ID. 337 func HexID(in string) ID { 338 id, err := ParseID(in) 339 if err != nil { 340 panic(err) 341 } 342 return id 343 } 344 345 func ParseID(in string) (ID, error) { 346 var id ID 347 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 348 if err != nil { 349 return id, err 350 } else if len(b) != len(id) { 351 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 352 } 353 copy(id[:], b) 354 return id, nil 355 } 356 357 // DistCmp compares the distances a->target and b->target. 358 // Returns -1 if a is closer to target, 1 if b is closer to target 359 // and 0 if they are equal. 360 func DistCmp(target, a, b ID) int { 361 for i := range target { 362 da := a[i] ^ target[i] 363 db := b[i] ^ target[i] 364 if da > db { 365 return 1 366 } else if da < db { 367 return -1 368 } 369 } 370 return 0 371 } 372 373 // LogDist returns the logarithmic distance between a and b, log2(a ^ b). 374 func LogDist(a, b ID) int { 375 lz := 0 376 for i := range a { 377 x := a[i] ^ b[i] 378 if x == 0 { 379 lz += 8 380 } else { 381 lz += bits.LeadingZeros8(x) 382 break 383 } 384 } 385 return len(a)*8 - lz 386 }