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