github.com/dominant-strategies/go-quai@v0.28.2/p2p/discover/v5_udp.go (about) 1 // Copyright 2019 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 "bytes" 21 "context" 22 "crypto/ecdsa" 23 crand "crypto/rand" 24 "errors" 25 "fmt" 26 "io" 27 "math" 28 "net" 29 "sync" 30 "time" 31 32 "github.com/dominant-strategies/go-quai/common/mclock" 33 "github.com/dominant-strategies/go-quai/log" 34 "github.com/dominant-strategies/go-quai/p2p/discover/v5wire" 35 "github.com/dominant-strategies/go-quai/p2p/enode" 36 "github.com/dominant-strategies/go-quai/p2p/enr" 37 "github.com/dominant-strategies/go-quai/p2p/netutil" 38 ) 39 40 const ( 41 lookupRequestLimit = 3 // max requests against a single node during lookup 42 findnodeResultLimit = 16 // applies in FINDNODE handler 43 totalNodesResponseLimit = 5 // applies in waitForNodes 44 nodesResponseItemLimit = 3 // applies in sendNodes 45 46 respTimeoutV5 = 700 * time.Millisecond 47 ) 48 49 // codecV5 is implemented by v5wire.Codec (and testCodec). 50 // 51 // The UDPv5 transport is split into two objects: the codec object deals with 52 // encoding/decoding and with the handshake; the UDPv5 object handles higher-level concerns. 53 type codecV5 interface { 54 // Encode encodes a packet. 55 Encode(enode.ID, string, v5wire.Packet, *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) 56 57 // decode decodes a packet. It returns a *v5wire.Unknown packet if decryption fails. 58 // The *enode.Node return value is non-nil when the input contains a handshake response. 59 Decode([]byte, string) (enode.ID, *enode.Node, v5wire.Packet, error) 60 } 61 62 // UDPv5 is the implementation of protocol version 5. 63 type UDPv5 struct { 64 // static fields 65 conn UDPConn 66 tab *Table 67 netrestrict *netutil.Netlist 68 priv *ecdsa.PrivateKey 69 localNode *enode.LocalNode 70 db *enode.DB 71 log *log.Logger 72 clock mclock.Clock 73 validSchemes enr.IdentityScheme 74 75 // talkreq handler registry 76 trlock sync.Mutex 77 trhandlers map[string]TalkRequestHandler 78 79 // channels into dispatch 80 packetInCh chan ReadPacket 81 readNextCh chan struct{} 82 callCh chan *callV5 83 callDoneCh chan *callV5 84 respTimeoutCh chan *callTimeout 85 86 // state of dispatch 87 codec codecV5 88 activeCallByNode map[enode.ID]*callV5 89 activeCallByAuth map[v5wire.Nonce]*callV5 90 callQueue map[enode.ID][]*callV5 91 92 // shutdown stuff 93 closeOnce sync.Once 94 closeCtx context.Context 95 cancelCloseCtx context.CancelFunc 96 wg sync.WaitGroup 97 } 98 99 // TalkRequestHandler callback processes a talk request and optionally returns a reply 100 type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte 101 102 // callV5 represents a remote procedure call against another node. 103 type callV5 struct { 104 node *enode.Node 105 packet v5wire.Packet 106 responseType byte // expected packet type of response 107 reqid []byte 108 ch chan v5wire.Packet // responses sent here 109 err chan error // errors sent here 110 111 // Valid for active calls only: 112 nonce v5wire.Nonce // nonce of request packet 113 handshakeCount int // # times we attempted handshake for this call 114 challenge *v5wire.Whoareyou // last sent handshake challenge 115 timeout mclock.Timer 116 } 117 118 // callTimeout is the response timeout event of a call. 119 type callTimeout struct { 120 c *callV5 121 timer mclock.Timer 122 } 123 124 // ListenV5 listens on the given connection. 125 func ListenV5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { 126 t, err := newUDPv5(conn, ln, cfg) 127 if err != nil { 128 return nil, err 129 } 130 go t.tab.loop() 131 t.wg.Add(2) 132 go t.readLoop() 133 go t.dispatch() 134 return t, nil 135 } 136 137 // newUDPv5 creates a UDPv5 transport, but doesn't start any goroutines. 138 func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { 139 closeCtx, cancelCloseCtx := context.WithCancel(context.Background()) 140 cfg = cfg.withDefaults() 141 t := &UDPv5{ 142 // static fields 143 conn: conn, 144 localNode: ln, 145 db: ln.Database(), 146 netrestrict: cfg.NetRestrict, 147 priv: cfg.PrivateKey, 148 log: &log.Log, 149 validSchemes: cfg.ValidSchemes, 150 clock: cfg.Clock, 151 trhandlers: make(map[string]TalkRequestHandler), 152 // channels into dispatch 153 packetInCh: make(chan ReadPacket, 1), 154 readNextCh: make(chan struct{}, 1), 155 callCh: make(chan *callV5), 156 callDoneCh: make(chan *callV5), 157 respTimeoutCh: make(chan *callTimeout), 158 // state of dispatch 159 codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock), 160 activeCallByNode: make(map[enode.ID]*callV5), 161 activeCallByAuth: make(map[v5wire.Nonce]*callV5), 162 callQueue: make(map[enode.ID][]*callV5), 163 // shutdown 164 closeCtx: closeCtx, 165 cancelCloseCtx: cancelCloseCtx, 166 } 167 tab, err := newTable(t, t.db, cfg.Bootnodes, *cfg.Log) 168 if err != nil { 169 return nil, err 170 } 171 t.tab = tab 172 return t, nil 173 } 174 175 // Self returns the local node record. 176 func (t *UDPv5) Self() *enode.Node { 177 return t.localNode.Node() 178 } 179 180 // Close shuts down packet processing. 181 func (t *UDPv5) Close() { 182 t.closeOnce.Do(func() { 183 t.cancelCloseCtx() 184 t.conn.Close() 185 t.wg.Wait() 186 t.tab.close() 187 }) 188 } 189 190 // Ping sends a ping message to the given node. 191 func (t *UDPv5) Ping(n *enode.Node) error { 192 _, err := t.ping(n) 193 return err 194 } 195 196 // Resolve searches for a specific node with the given ID and tries to get the most recent 197 // version of the node record for it. It returns n if the node could not be resolved. 198 func (t *UDPv5) Resolve(n *enode.Node) *enode.Node { 199 if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { 200 n = intable 201 } 202 // Try asking directly. This works if the node is still responding on the endpoint we have. 203 if resp, err := t.RequestENR(n); err == nil { 204 return resp 205 } 206 // Otherwise do a network lookup. 207 result := t.Lookup(n.ID()) 208 for _, rn := range result { 209 if rn.ID() == n.ID() && rn.Seq() > n.Seq() { 210 return rn 211 } 212 } 213 return n 214 } 215 216 // AllNodes returns all the nodes stored in the local table. 217 func (t *UDPv5) AllNodes() []*enode.Node { 218 t.tab.mutex.Lock() 219 defer t.tab.mutex.Unlock() 220 nodes := make([]*enode.Node, 0) 221 222 for _, b := range &t.tab.buckets { 223 for _, n := range b.entries { 224 nodes = append(nodes, unwrapNode(n)) 225 } 226 } 227 return nodes 228 } 229 230 // LocalNode returns the current local node running the 231 // protocol. 232 func (t *UDPv5) LocalNode() *enode.LocalNode { 233 return t.localNode 234 } 235 236 // RegisterTalkHandler adds a handler for 'talk requests'. The handler function is called 237 // whenever a request for the given protocol is received and should return the response 238 // data or nil. 239 func (t *UDPv5) RegisterTalkHandler(protocol string, handler TalkRequestHandler) { 240 t.trlock.Lock() 241 defer t.trlock.Unlock() 242 t.trhandlers[protocol] = handler 243 } 244 245 // TalkRequest sends a talk request to n and waits for a response. 246 func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]byte, error) { 247 req := &v5wire.TalkRequest{Protocol: protocol, Message: request} 248 resp := t.call(n, v5wire.TalkResponseMsg, req) 249 defer t.callDone(resp) 250 select { 251 case respMsg := <-resp.ch: 252 return respMsg.(*v5wire.TalkResponse).Message, nil 253 case err := <-resp.err: 254 return nil, err 255 } 256 } 257 258 // RandomNodes returns an iterator that finds random nodes in the DHT. 259 func (t *UDPv5) RandomNodes() enode.Iterator { 260 if t.tab.len() == 0 { 261 // All nodes were dropped, refresh. The very first query will hit this 262 // case and run the bootstrapping logic. 263 <-t.tab.refresh() 264 } 265 266 return newLookupIterator(t.closeCtx, t.newRandomLookup) 267 } 268 269 // Lookup performs a recursive lookup for the given target. 270 // It returns the closest nodes to target. 271 func (t *UDPv5) Lookup(target enode.ID) []*enode.Node { 272 return t.newLookup(t.closeCtx, target).run() 273 } 274 275 // lookupRandom looks up a random target. 276 // This is needed to satisfy the transport interface. 277 func (t *UDPv5) lookupRandom() []*enode.Node { 278 return t.newRandomLookup(t.closeCtx).run() 279 } 280 281 // lookupSelf looks up our own node ID. 282 // This is needed to satisfy the transport interface. 283 func (t *UDPv5) lookupSelf() []*enode.Node { 284 return t.newLookup(t.closeCtx, t.Self().ID()).run() 285 } 286 287 func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup { 288 var target enode.ID 289 crand.Read(target[:]) 290 return t.newLookup(ctx, target) 291 } 292 293 func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup { 294 return newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { 295 return t.lookupWorker(n, target) 296 }) 297 } 298 299 // lookupWorker performs FINDNODE calls against a single node during lookup. 300 func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { 301 var ( 302 dists = lookupDistances(target, destNode.ID()) 303 nodes = nodesByDistance{target: target} 304 err error 305 ) 306 var r []*enode.Node 307 r, err = t.findnode(unwrapNode(destNode), dists) 308 if err == errClosed { 309 return nil, err 310 } 311 for _, n := range r { 312 if n.ID() != t.Self().ID() { 313 nodes.push(wrapNode(n), findnodeResultLimit) 314 } 315 } 316 return nodes.entries, err 317 } 318 319 // lookupDistances computes the distance parameter for FINDNODE calls to dest. 320 // It chooses distances adjacent to logdist(target, dest), e.g. for a target 321 // with logdist(target, dest) = 255 the result is [255, 256, 254]. 322 func lookupDistances(target, dest enode.ID) (dists []uint) { 323 td := enode.LogDist(target, dest) 324 dists = append(dists, uint(td)) 325 for i := 1; len(dists) < lookupRequestLimit; i++ { 326 if td+i < 256 { 327 dists = append(dists, uint(td+i)) 328 } 329 if td-i > 0 { 330 dists = append(dists, uint(td-i)) 331 } 332 } 333 return dists 334 } 335 336 // ping calls PING on a node and waits for a PONG response. 337 func (t *UDPv5) ping(n *enode.Node) (uint64, error) { 338 req := &v5wire.Ping{ENRSeq: t.localNode.Node().Seq()} 339 resp := t.call(n, v5wire.PongMsg, req) 340 defer t.callDone(resp) 341 342 select { 343 case pong := <-resp.ch: 344 return pong.(*v5wire.Pong).ENRSeq, nil 345 case err := <-resp.err: 346 return 0, err 347 } 348 } 349 350 // requestENR requests n's record. 351 func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { 352 nodes, err := t.findnode(n, []uint{0}) 353 if err != nil { 354 return nil, err 355 } 356 if len(nodes) != 1 { 357 return nil, fmt.Errorf("%d nodes in response for distance zero", len(nodes)) 358 } 359 return nodes[0], nil 360 } 361 362 // findnode calls FINDNODE on a node and waits for responses. 363 func (t *UDPv5) findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) { 364 resp := t.call(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances}) 365 return t.waitForNodes(resp, distances) 366 } 367 368 // waitForNodes waits for NODES responses to the given call. 369 func (t *UDPv5) waitForNodes(c *callV5, distances []uint) ([]*enode.Node, error) { 370 defer t.callDone(c) 371 372 var ( 373 nodes []*enode.Node 374 seen = make(map[enode.ID]struct{}) 375 received, total = 0, -1 376 ) 377 for { 378 select { 379 case responseP := <-c.ch: 380 response := responseP.(*v5wire.Nodes) 381 for _, record := range response.Nodes { 382 node, err := t.verifyResponseNode(c, record, distances, seen) 383 if err != nil { 384 t.log.Debug("Invalid record in "+response.Name(), "id", c.node.ID(), "err", err) 385 continue 386 } 387 nodes = append(nodes, node) 388 } 389 if total == -1 { 390 total = min(int(response.Total), totalNodesResponseLimit) 391 } 392 if received++; received == total { 393 return nodes, nil 394 } 395 case err := <-c.err: 396 return nodes, err 397 } 398 } 399 } 400 401 // verifyResponseNode checks validity of a record in a NODES response. 402 func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, seen map[enode.ID]struct{}) (*enode.Node, error) { 403 node, err := enode.New(t.validSchemes, r) 404 if err != nil { 405 return nil, err 406 } 407 if err := netutil.CheckRelayIP(c.node.IP(), node.IP()); err != nil { 408 return nil, err 409 } 410 if c.node.UDP() <= 1024 { 411 return nil, errLowPort 412 } 413 if distances != nil { 414 nd := enode.LogDist(c.node.ID(), node.ID()) 415 if !containsUint(uint(nd), distances) { 416 return nil, errors.New("does not match any requested distance") 417 } 418 } 419 if _, ok := seen[node.ID()]; ok { 420 return nil, fmt.Errorf("duplicate record") 421 } 422 seen[node.ID()] = struct{}{} 423 return node, nil 424 } 425 426 func containsUint(x uint, xs []uint) bool { 427 for _, v := range xs { 428 if x == v { 429 return true 430 } 431 } 432 return false 433 } 434 435 // call sends the given call and sets up a handler for response packets (of message type 436 // responseType). Responses are dispatched to the call's response channel. 437 func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet) *callV5 { 438 c := &callV5{ 439 node: node, 440 packet: packet, 441 responseType: responseType, 442 reqid: make([]byte, 8), 443 ch: make(chan v5wire.Packet, 1), 444 err: make(chan error, 1), 445 } 446 // Assign request ID. 447 crand.Read(c.reqid) 448 packet.SetRequestID(c.reqid) 449 // Send call to dispatch. 450 select { 451 case t.callCh <- c: 452 case <-t.closeCtx.Done(): 453 c.err <- errClosed 454 } 455 return c 456 } 457 458 // callDone tells dispatch that the active call is done. 459 func (t *UDPv5) callDone(c *callV5) { 460 // This needs a loop because further responses may be incoming until the 461 // send to callDoneCh has completed. Such responses need to be discarded 462 // in order to avoid blocking the dispatch loop. 463 for { 464 select { 465 case <-c.ch: 466 // late response, discard. 467 case <-c.err: 468 // late error, discard. 469 case t.callDoneCh <- c: 470 return 471 case <-t.closeCtx.Done(): 472 return 473 } 474 } 475 } 476 477 // dispatch runs in its own goroutine, handles incoming packets and deals with calls. 478 // 479 // For any destination node there is at most one 'active call', stored in the t.activeCall* 480 // maps. A call is made active when it is sent. The active call can be answered by a 481 // matching response, in which case c.ch receives the response; or by timing out, in which case 482 // c.err receives the error. When the function that created the call signals the active 483 // call is done through callDone, the next call from the call queue is started. 484 // 485 // Calls may also be answered by a WHOAREYOU packet referencing the call packet's authTag. 486 // When that happens the call is simply re-sent to complete the handshake. We allow one 487 // handshake attempt per call. 488 func (t *UDPv5) dispatch() { 489 defer t.wg.Done() 490 491 // Arm first read. 492 t.readNextCh <- struct{}{} 493 494 for { 495 select { 496 case c := <-t.callCh: 497 id := c.node.ID() 498 t.callQueue[id] = append(t.callQueue[id], c) 499 t.sendNextCall(id) 500 501 case ct := <-t.respTimeoutCh: 502 active := t.activeCallByNode[ct.c.node.ID()] 503 if ct.c == active && ct.timer == active.timeout { 504 ct.c.err <- errTimeout 505 } 506 507 case c := <-t.callDoneCh: 508 id := c.node.ID() 509 active := t.activeCallByNode[id] 510 if active != c { 511 panic("BUG: callDone for inactive call") 512 } 513 c.timeout.Stop() 514 delete(t.activeCallByAuth, c.nonce) 515 delete(t.activeCallByNode, id) 516 t.sendNextCall(id) 517 518 case p := <-t.packetInCh: 519 t.handlePacket(p.Data, p.Addr) 520 // Arm next read. 521 t.readNextCh <- struct{}{} 522 523 case <-t.closeCtx.Done(): 524 close(t.readNextCh) 525 for id, queue := range t.callQueue { 526 for _, c := range queue { 527 c.err <- errClosed 528 } 529 delete(t.callQueue, id) 530 } 531 for id, c := range t.activeCallByNode { 532 c.err <- errClosed 533 delete(t.activeCallByNode, id) 534 delete(t.activeCallByAuth, c.nonce) 535 } 536 return 537 } 538 } 539 } 540 541 // startResponseTimeout sets the response timer for a call. 542 func (t *UDPv5) startResponseTimeout(c *callV5) { 543 if c.timeout != nil { 544 c.timeout.Stop() 545 } 546 var ( 547 timer mclock.Timer 548 done = make(chan struct{}) 549 ) 550 timer = t.clock.AfterFunc(respTimeoutV5, func() { 551 <-done 552 select { 553 case t.respTimeoutCh <- &callTimeout{c, timer}: 554 case <-t.closeCtx.Done(): 555 } 556 }) 557 c.timeout = timer 558 close(done) 559 } 560 561 // sendNextCall sends the next call in the call queue if there is no active call. 562 func (t *UDPv5) sendNextCall(id enode.ID) { 563 queue := t.callQueue[id] 564 if len(queue) == 0 || t.activeCallByNode[id] != nil { 565 return 566 } 567 t.activeCallByNode[id] = queue[0] 568 t.sendCall(t.activeCallByNode[id]) 569 if len(queue) == 1 { 570 delete(t.callQueue, id) 571 } else { 572 copy(queue, queue[1:]) 573 t.callQueue[id] = queue[:len(queue)-1] 574 } 575 } 576 577 // sendCall encodes and sends a request packet to the call's recipient node. 578 // This performs a handshake if needed. 579 func (t *UDPv5) sendCall(c *callV5) { 580 // The call might have a nonce from a previous handshake attempt. Remove the entry for 581 // the old nonce because we're about to generate a new nonce for this call. 582 if c.nonce != (v5wire.Nonce{}) { 583 delete(t.activeCallByAuth, c.nonce) 584 } 585 586 addr := &net.UDPAddr{IP: c.node.IP(), Port: c.node.UDP()} 587 newNonce, _ := t.send(c.node.ID(), addr, c.packet, c.challenge) 588 c.nonce = newNonce 589 t.activeCallByAuth[newNonce] = c 590 t.startResponseTimeout(c) 591 } 592 593 // sendResponse sends a response packet to the given node. 594 // This doesn't trigger a handshake even if no keys are available. 595 func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) error { 596 _, err := t.send(toID, toAddr, packet, nil) 597 return err 598 } 599 600 // send sends a packet to the given node. 601 func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { 602 addr := toAddr.String() 603 enc, nonce, err := t.codec.Encode(toID, addr, packet, c) 604 if err != nil { 605 t.log.Warn(">> "+packet.Name(), "id", toID, "addr", addr, "err", err) 606 return nonce, err 607 } 608 _, err = t.conn.WriteToUDP(enc, toAddr) 609 t.log.Trace(">> "+packet.Name(), "id", toID, "addr", addr) 610 return nonce, err 611 } 612 613 // readLoop runs in its own goroutine and reads packets from the network. 614 func (t *UDPv5) readLoop() { 615 defer t.wg.Done() 616 617 buf := make([]byte, maxPacketSize) 618 for range t.readNextCh { 619 nbytes, from, err := t.conn.ReadFromUDP(buf) 620 if netutil.IsTemporaryError(err) { 621 // Ignore temporary read errors. 622 t.log.Debug("Temporary UDP read error", "err", err) 623 continue 624 } else if err != nil { 625 // Shut down the loop for permament errors. 626 if err != io.EOF { 627 t.log.Debug("UDP read error", "err", err) 628 } 629 return 630 } 631 t.dispatchReadPacket(from, buf[:nbytes]) 632 } 633 } 634 635 // dispatchReadPacket sends a packet into the dispatch loop. 636 func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { 637 select { 638 case t.packetInCh <- ReadPacket{content, from}: 639 return true 640 case <-t.closeCtx.Done(): 641 return false 642 } 643 } 644 645 // handlePacket decodes and processes an incoming packet from the network. 646 func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { 647 addr := fromAddr.String() 648 fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr) 649 if err != nil { 650 t.log.Debug("Bad discv5 packet", "id", fromID, "addr", addr, "err", err) 651 return err 652 } 653 if fromNode != nil { 654 // Handshake succeeded, add to table. 655 t.tab.addSeenNode(wrapNode(fromNode)) 656 } 657 if packet.Kind() != v5wire.WhoareyouPacket { 658 // WHOAREYOU logged separately to report errors. 659 t.log.Trace("<< "+packet.Name(), "id", fromID, "addr", addr) 660 } 661 t.handle(packet, fromID, fromAddr) 662 return nil 663 } 664 665 // handleCallResponse dispatches a response packet to the call waiting for it. 666 func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr *net.UDPAddr, p v5wire.Packet) bool { 667 ac := t.activeCallByNode[fromID] 668 if ac == nil || !bytes.Equal(p.RequestID(), ac.reqid) { 669 t.log.Debug(fmt.Sprintf("Unsolicited/late %s response", p.Name()), "id", fromID, "addr", fromAddr) 670 return false 671 } 672 if !fromAddr.IP.Equal(ac.node.IP()) || fromAddr.Port != ac.node.UDP() { 673 t.log.Debug(fmt.Sprintf("%s from wrong endpoint", p.Name()), "id", fromID, "addr", fromAddr) 674 return false 675 } 676 if p.Kind() != ac.responseType { 677 t.log.Debug(fmt.Sprintf("Wrong discv5 response type %s", p.Name()), "id", fromID, "addr", fromAddr) 678 return false 679 } 680 t.startResponseTimeout(ac) 681 ac.ch <- p 682 return true 683 } 684 685 // getNode looks for a node record in table and database. 686 func (t *UDPv5) getNode(id enode.ID) *enode.Node { 687 if n := t.tab.getNode(id); n != nil { 688 return n 689 } 690 if n := t.localNode.Database().Node(id); n != nil { 691 return n 692 } 693 return nil 694 } 695 696 // handle processes incoming packets according to their message type. 697 func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) { 698 switch p := p.(type) { 699 case *v5wire.Unknown: 700 t.handleUnknown(p, fromID, fromAddr) 701 case *v5wire.Whoareyou: 702 t.handleWhoareyou(p, fromID, fromAddr) 703 case *v5wire.Ping: 704 t.handlePing(p, fromID, fromAddr) 705 case *v5wire.Pong: 706 if t.handleCallResponse(fromID, fromAddr, p) { 707 t.localNode.UDPEndpointStatement(fromAddr, &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)}) 708 } 709 case *v5wire.Findnode: 710 t.handleFindnode(p, fromID, fromAddr) 711 case *v5wire.Nodes: 712 t.handleCallResponse(fromID, fromAddr, p) 713 case *v5wire.TalkRequest: 714 t.handleTalkRequest(p, fromID, fromAddr) 715 case *v5wire.TalkResponse: 716 t.handleCallResponse(fromID, fromAddr, p) 717 } 718 } 719 720 // handleUnknown initiates a handshake by responding with WHOAREYOU. 721 func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr *net.UDPAddr) { 722 challenge := &v5wire.Whoareyou{Nonce: p.Nonce} 723 crand.Read(challenge.IDNonce[:]) 724 if n := t.getNode(fromID); n != nil { 725 challenge.Node = n 726 challenge.RecordSeq = n.Seq() 727 } 728 t.sendResponse(fromID, fromAddr, challenge) 729 } 730 731 var ( 732 errChallengeNoCall = errors.New("no matching call") 733 errChallengeTwice = errors.New("second handshake") 734 ) 735 736 // handleWhoareyou resends the active call as a handshake packet. 737 func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr *net.UDPAddr) { 738 c, err := t.matchWithCall(fromID, p.Nonce) 739 if err != nil { 740 t.log.Debug("Invalid "+p.Name(), "addr", fromAddr, "err", err) 741 return 742 } 743 744 // Resend the call that was answered by WHOAREYOU. 745 t.log.Trace("<< "+p.Name(), "id", c.node.ID(), "addr", fromAddr) 746 c.handshakeCount++ 747 c.challenge = p 748 p.Node = c.node 749 t.sendCall(c) 750 } 751 752 // matchWithCall checks whether a handshake attempt matches the active call. 753 func (t *UDPv5) matchWithCall(fromID enode.ID, nonce v5wire.Nonce) (*callV5, error) { 754 c := t.activeCallByAuth[nonce] 755 if c == nil { 756 return nil, errChallengeNoCall 757 } 758 if c.handshakeCount > 0 { 759 return nil, errChallengeTwice 760 } 761 return c, nil 762 } 763 764 // handlePing sends a PONG response. 765 func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr *net.UDPAddr) { 766 remoteIP := fromAddr.IP 767 // Handle IPv4 mapped IPv6 addresses in the 768 // event the local node is binded to an 769 // ipv6 interface. 770 if remoteIP.To4() != nil { 771 remoteIP = remoteIP.To4() 772 } 773 t.sendResponse(fromID, fromAddr, &v5wire.Pong{ 774 ReqID: p.ReqID, 775 ToIP: remoteIP, 776 ToPort: uint16(fromAddr.Port), 777 ENRSeq: t.localNode.Node().Seq(), 778 }) 779 } 780 781 // handleFindnode returns nodes to the requester. 782 func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr *net.UDPAddr) { 783 nodes := t.collectTableNodes(fromAddr.IP, p.Distances, findnodeResultLimit) 784 for _, resp := range packNodes(p.ReqID, nodes) { 785 t.sendResponse(fromID, fromAddr, resp) 786 } 787 } 788 789 // collectTableNodes creates a FINDNODE result set for the given distances. 790 func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*enode.Node { 791 var nodes []*enode.Node 792 var processed = make(map[uint]struct{}) 793 for _, dist := range distances { 794 // Reject duplicate / invalid distances. 795 _, seen := processed[dist] 796 if seen || dist > 256 { 797 continue 798 } 799 800 // Get the nodes. 801 var bn []*enode.Node 802 if dist == 0 { 803 bn = []*enode.Node{t.Self()} 804 } else if dist <= 256 { 805 t.tab.mutex.Lock() 806 bn = unwrapNodes(t.tab.bucketAtDistance(int(dist)).entries) 807 t.tab.mutex.Unlock() 808 } 809 processed[dist] = struct{}{} 810 811 // Apply some pre-checks to avoid sending invalid nodes. 812 for _, n := range bn { 813 // TODO livenessChecks > 1 814 if netutil.CheckRelayIP(rip, n.IP()) != nil { 815 continue 816 } 817 nodes = append(nodes, n) 818 if len(nodes) >= limit { 819 return nodes 820 } 821 } 822 } 823 return nodes 824 } 825 826 // packNodes creates NODES response packets for the given node list. 827 func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { 828 if len(nodes) == 0 { 829 return []*v5wire.Nodes{{ReqID: reqid, Total: 1}} 830 } 831 832 total := uint8(math.Ceil(float64(len(nodes)) / 3)) 833 var resp []*v5wire.Nodes 834 for len(nodes) > 0 { 835 p := &v5wire.Nodes{ReqID: reqid, Total: total} 836 items := min(nodesResponseItemLimit, len(nodes)) 837 for i := 0; i < items; i++ { 838 p.Nodes = append(p.Nodes, nodes[i].Record()) 839 } 840 nodes = nodes[items:] 841 resp = append(resp, p) 842 } 843 return resp 844 } 845 846 // handleTalkRequest runs the talk request handler of the requested protocol. 847 func (t *UDPv5) handleTalkRequest(p *v5wire.TalkRequest, fromID enode.ID, fromAddr *net.UDPAddr) { 848 t.trlock.Lock() 849 handler := t.trhandlers[p.Protocol] 850 t.trlock.Unlock() 851 852 var response []byte 853 if handler != nil { 854 response = handler(fromID, fromAddr, p.Message) 855 } 856 resp := &v5wire.TalkResponse{ReqID: p.ReqID, Message: response} 857 t.sendResponse(fromID, fromAddr, resp) 858 }