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