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  }