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