github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/p2p/discover/v5_udp.go (about)

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