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