github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/p2p/discover/node.go (about) 1 // Copyright 2015 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 discover 18 19 import ( 20 "crypto/ecdsa" 21 "crypto/elliptic" 22 "encoding/hex" 23 "errors" 24 "fmt" 25 "math/big" 26 "math/rand" 27 "net" 28 "net/url" 29 "regexp" 30 "strconv" 31 "strings" 32 "time" 33 34 "github.com/FusionFoundation/efsn/common" 35 "github.com/FusionFoundation/efsn/crypto" 36 "github.com/FusionFoundation/efsn/crypto/secp256k1" 37 ) 38 39 const NodeIDBits = 512 40 41 // Node represents a host on the network. 42 // The fields of Node may not be modified. 43 type Node struct { 44 IP net.IP // len 4 for IPv4 or 16 for IPv6 45 UDP, TCP uint16 // port numbers 46 ID NodeID // the node's public key 47 48 // This is a cached copy of sha3(ID) which is used for node 49 // distance calculations. This is part of Node in order to make it 50 // possible to write tests that need a node at a certain distance. 51 // In those tests, the content of sha will not actually correspond 52 // with ID. 53 sha common.Hash 54 55 // Time when the node was added to the table. 56 addedAt time.Time 57 } 58 59 // NewNode creates a new node. It is mostly meant to be used for 60 // testing purposes. 61 func NewNode(id NodeID, ip net.IP, udpPort, tcpPort uint16) *Node { 62 if ipv4 := ip.To4(); ipv4 != nil { 63 ip = ipv4 64 } 65 return &Node{ 66 IP: ip, 67 UDP: udpPort, 68 TCP: tcpPort, 69 ID: id, 70 sha: crypto.Keccak256Hash(id[:]), 71 } 72 } 73 74 func (n *Node) addr() *net.UDPAddr { 75 return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)} 76 } 77 78 // Incomplete returns true for nodes with no IP address. 79 func (n *Node) Incomplete() bool { 80 return n.IP == nil 81 } 82 83 // checks whether n is a valid complete node. 84 func (n *Node) validateComplete() error { 85 if n.Incomplete() { 86 return errors.New("incomplete node") 87 } 88 if n.UDP == 0 { 89 return errors.New("missing UDP port") 90 } 91 if n.TCP == 0 { 92 return errors.New("missing TCP port") 93 } 94 if n.IP.IsMulticast() || n.IP.IsUnspecified() { 95 return errors.New("invalid IP (multicast/unspecified)") 96 } 97 _, err := n.ID.Pubkey() // validate the key (on curve, etc.) 98 return err 99 } 100 101 // The string representation of a Node is a URL. 102 // Please see ParseNode for a description of the format. 103 func (n *Node) String() string { 104 u := url.URL{Scheme: "enode"} 105 if n.Incomplete() { 106 u.Host = fmt.Sprintf("%x", n.ID[:]) 107 } else { 108 addr := net.TCPAddr{IP: n.IP, Port: int(n.TCP)} 109 u.User = url.User(fmt.Sprintf("%x", n.ID[:])) 110 u.Host = addr.String() 111 if n.UDP != n.TCP { 112 u.RawQuery = "discport=" + strconv.Itoa(int(n.UDP)) 113 } 114 } 115 return u.String() 116 } 117 118 var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$") 119 120 // ParseNode parses a node designator. 121 // 122 // There are two basic forms of node designators 123 // - incomplete nodes, which only have the public key (node ID) 124 // - complete nodes, which contain the public key and IP/Port information 125 // 126 // For incomplete nodes, the designator must look like one of these 127 // 128 // enode://<hex node id> 129 // <hex node id> 130 // 131 // For complete nodes, the node ID is encoded in the username portion 132 // of the URL, separated from the host by an @ sign. The hostname can 133 // only be given as an IP address, DNS domain names are not allowed. 134 // The port in the host name section is the TCP listening port. If the 135 // TCP and UDP (discovery) ports differ, the UDP port is specified as 136 // query parameter "discport". 137 // 138 // In the following example, the node URL describes 139 // a node with IP address 10.3.58.6, TCP listening port 40404 140 // and UDP discovery port 40401. 141 // 142 // enode://<hex node id>@10.3.58.6:40404?discport=40401 143 func ParseNode(rawurl string) (*Node, error) { 144 if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil { 145 id, err := HexID(m[1]) 146 if err != nil { 147 return nil, fmt.Errorf("invalid node ID (%v)", err) 148 } 149 return NewNode(id, nil, 0, 0), nil 150 } 151 return parseComplete(rawurl) 152 } 153 154 func parseComplete(rawurl string) (*Node, error) { 155 var ( 156 id NodeID 157 ip net.IP 158 tcpPort, udpPort uint64 159 ) 160 u, err := url.Parse(rawurl) 161 if err != nil { 162 return nil, err 163 } 164 if u.Scheme != "enode" { 165 return nil, errors.New("invalid URL scheme, want \"enode\"") 166 } 167 // Parse the Node ID from the user portion. 168 if u.User == nil { 169 return nil, errors.New("does not contain node ID") 170 } 171 if id, err = HexID(u.User.String()); err != nil { 172 return nil, fmt.Errorf("invalid node ID (%v)", err) 173 } 174 // Parse the IP address. 175 host, port, err := net.SplitHostPort(u.Host) 176 if err != nil { 177 return nil, fmt.Errorf("invalid host: %v", err) 178 } 179 180 ips, err := net.LookupIP(host) 181 if err != nil || len(ips) < 1 { 182 return nil, errors.New("invalid host") 183 } 184 ip = ips[0] 185 // Ensure the IP is 4 bytes long for IPv4 addresses. 186 if ipv4 := ip.To4(); ipv4 != nil { 187 ip = ipv4 188 } 189 // Parse the port numbers. 190 if tcpPort, err = strconv.ParseUint(port, 10, 16); err != nil { 191 return nil, errors.New("invalid port") 192 } 193 udpPort = tcpPort 194 qv := u.Query() 195 if qv.Get("discport") != "" { 196 udpPort, err = strconv.ParseUint(qv.Get("discport"), 10, 16) 197 if err != nil { 198 return nil, errors.New("invalid discport in query") 199 } 200 } 201 return NewNode(id, ip, uint16(udpPort), uint16(tcpPort)), nil 202 } 203 204 // MustParseNode parses a node URL. It panics if the URL is not valid. 205 func MustParseNode(rawurl string) *Node { 206 n, err := ParseNode(rawurl) 207 if err != nil { 208 panic("invalid node URL: " + err.Error()) 209 } 210 return n 211 } 212 213 // MarshalText implements encoding.TextMarshaler. 214 func (n *Node) MarshalText() ([]byte, error) { 215 return []byte(n.String()), nil 216 } 217 218 // UnmarshalText implements encoding.TextUnmarshaler. 219 func (n *Node) UnmarshalText(text []byte) error { 220 dec, err := ParseNode(string(text)) 221 if err == nil { 222 *n = *dec 223 } 224 return err 225 } 226 227 // NodeID is a unique identifier for each node. 228 // The node identifier is a marshaled elliptic curve public key. 229 type NodeID [NodeIDBits / 8]byte 230 231 // Bytes returns a byte slice representation of the NodeID 232 func (n NodeID) Bytes() []byte { 233 return n[:] 234 } 235 236 // NodeID prints as a long hexadecimal number. 237 func (n NodeID) String() string { 238 return fmt.Sprintf("%x", n[:]) 239 } 240 241 // The Go syntax representation of a NodeID is a call to HexID. 242 func (n NodeID) GoString() string { 243 return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) 244 } 245 246 // TerminalString returns a shortened hex string for terminal logging. 247 func (n NodeID) TerminalString() string { 248 return hex.EncodeToString(n[:8]) 249 } 250 251 // MarshalText implements the encoding.TextMarshaler interface. 252 func (n NodeID) MarshalText() ([]byte, error) { 253 return []byte(hex.EncodeToString(n[:])), nil 254 } 255 256 // UnmarshalText implements the encoding.TextUnmarshaler interface. 257 func (n *NodeID) UnmarshalText(text []byte) error { 258 id, err := HexID(string(text)) 259 if err != nil { 260 return err 261 } 262 *n = id 263 return nil 264 } 265 266 // BytesID converts a byte slice to a NodeID 267 func BytesID(b []byte) (NodeID, error) { 268 var id NodeID 269 if len(b) != len(id) { 270 return id, fmt.Errorf("wrong length, want %d bytes", len(id)) 271 } 272 copy(id[:], b) 273 return id, nil 274 } 275 276 // MustBytesID converts a byte slice to a NodeID. 277 // It panics if the byte slice is not a valid NodeID. 278 func MustBytesID(b []byte) NodeID { 279 id, err := BytesID(b) 280 if err != nil { 281 panic(err) 282 } 283 return id 284 } 285 286 // HexID converts a hex string to a NodeID. 287 // The string may be prefixed with 0x. 288 func HexID(in string) (NodeID, error) { 289 var id NodeID 290 b, err := hex.DecodeString(strings.TrimPrefix(in, "0x")) 291 if err != nil { 292 return id, err 293 } else if len(b) != len(id) { 294 return id, fmt.Errorf("wrong length, want %d hex chars", len(id)*2) 295 } 296 copy(id[:], b) 297 return id, nil 298 } 299 300 // MustHexID converts a hex string to a NodeID. 301 // It panics if the string is not a valid NodeID. 302 func MustHexID(in string) NodeID { 303 id, err := HexID(in) 304 if err != nil { 305 panic(err) 306 } 307 return id 308 } 309 310 // PubkeyID returns a marshaled representation of the given public key. 311 func PubkeyID(pub *ecdsa.PublicKey) NodeID { 312 var id NodeID 313 pbytes := elliptic.Marshal(pub.Curve, pub.X, pub.Y) 314 if len(pbytes)-1 != len(id) { 315 panic(fmt.Errorf("need %d bit pubkey, got %d bits", (len(id)+1)*8, len(pbytes))) 316 } 317 copy(id[:], pbytes[1:]) 318 return id 319 } 320 321 // Pubkey returns the public key represented by the node ID. 322 // It returns an error if the ID is not a point on the curve. 323 func (id NodeID) Pubkey() (*ecdsa.PublicKey, error) { 324 p := &ecdsa.PublicKey{Curve: crypto.S256(), X: new(big.Int), Y: new(big.Int)} 325 half := len(id) / 2 326 p.X.SetBytes(id[:half]) 327 p.Y.SetBytes(id[half:]) 328 if !p.Curve.IsOnCurve(p.X, p.Y) { 329 return nil, errors.New("id is invalid secp256k1 curve point") 330 } 331 return p, nil 332 } 333 334 // recoverNodeID computes the public key used to sign the 335 // given hash from the signature. 336 func recoverNodeID(hash, sig []byte) (id NodeID, err error) { 337 pubkey, err := secp256k1.RecoverPubkey(hash, sig) 338 if err != nil { 339 return id, err 340 } 341 if len(pubkey)-1 != len(id) { 342 return id, fmt.Errorf("recovered pubkey has %d bits, want %d bits", len(pubkey)*8, (len(id)+1)*8) 343 } 344 for i := range id { 345 id[i] = pubkey[i+1] 346 } 347 return id, nil 348 } 349 350 // distcmp compares the distances a->target and b->target. 351 // Returns -1 if a is closer to target, 1 if b is closer to target 352 // and 0 if they are equal. 353 func distcmp(target, a, b common.Hash) int { 354 for i := range target { 355 da := a[i] ^ target[i] 356 db := b[i] ^ target[i] 357 if da > db { 358 return 1 359 } else if da < db { 360 return -1 361 } 362 } 363 return 0 364 } 365 366 // table of leading zero counts for bytes [0..255] 367 var lzcount = [256]int{ 368 8, 7, 6, 6, 5, 5, 5, 5, 369 4, 4, 4, 4, 4, 4, 4, 4, 370 3, 3, 3, 3, 3, 3, 3, 3, 371 3, 3, 3, 3, 3, 3, 3, 3, 372 2, 2, 2, 2, 2, 2, 2, 2, 373 2, 2, 2, 2, 2, 2, 2, 2, 374 2, 2, 2, 2, 2, 2, 2, 2, 375 2, 2, 2, 2, 2, 2, 2, 2, 376 1, 1, 1, 1, 1, 1, 1, 1, 377 1, 1, 1, 1, 1, 1, 1, 1, 378 1, 1, 1, 1, 1, 1, 1, 1, 379 1, 1, 1, 1, 1, 1, 1, 1, 380 1, 1, 1, 1, 1, 1, 1, 1, 381 1, 1, 1, 1, 1, 1, 1, 1, 382 1, 1, 1, 1, 1, 1, 1, 1, 383 1, 1, 1, 1, 1, 1, 1, 1, 384 0, 0, 0, 0, 0, 0, 0, 0, 385 0, 0, 0, 0, 0, 0, 0, 0, 386 0, 0, 0, 0, 0, 0, 0, 0, 387 0, 0, 0, 0, 0, 0, 0, 0, 388 0, 0, 0, 0, 0, 0, 0, 0, 389 0, 0, 0, 0, 0, 0, 0, 0, 390 0, 0, 0, 0, 0, 0, 0, 0, 391 0, 0, 0, 0, 0, 0, 0, 0, 392 0, 0, 0, 0, 0, 0, 0, 0, 393 0, 0, 0, 0, 0, 0, 0, 0, 394 0, 0, 0, 0, 0, 0, 0, 0, 395 0, 0, 0, 0, 0, 0, 0, 0, 396 0, 0, 0, 0, 0, 0, 0, 0, 397 0, 0, 0, 0, 0, 0, 0, 0, 398 0, 0, 0, 0, 0, 0, 0, 0, 399 0, 0, 0, 0, 0, 0, 0, 0, 400 } 401 402 // logdist returns the logarithmic distance between a and b, log2(a ^ b). 403 func logdist(a, b common.Hash) int { 404 lz := 0 405 for i := range a { 406 x := a[i] ^ b[i] 407 if x == 0 { 408 lz += 8 409 } else { 410 lz += lzcount[x] 411 break 412 } 413 } 414 return len(a)*8 - lz 415 } 416 417 // hashAtDistance returns a random hash such that logdist(a, b) == n 418 func hashAtDistance(a common.Hash, n int) (b common.Hash) { 419 if n == 0 { 420 return a 421 } 422 // flip bit at position n, fill the rest with random bits 423 b = a 424 pos := len(a) - n/8 - 1 425 bit := byte(0x01) << (byte(n%8) - 1) 426 if bit == 0 { 427 pos++ 428 bit = 0x80 429 } 430 b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits 431 for i := pos + 1; i < len(a); i++ { 432 b[i] = byte(rand.Intn(255)) 433 } 434 return b 435 }