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