github.com/xinfinOrg/xdposchain@v1.1.0/p2p/discover/udp.go (about)

     1  // Copyright 2015 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  	"container/list"
    22  	"crypto/ecdsa"
    23  	"errors"
    24  	"fmt"
    25  	"net"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/p2p/enode"
    32  	"github.com/ethereum/go-ethereum/p2p/netutil"
    33  	"github.com/ethereum/go-ethereum/rlp"
    34  )
    35  
    36  // Errors
    37  var (
    38  	errPacketTooSmall   = errors.New("too small")
    39  	errBadHash          = errors.New("bad hash")
    40  	errExpired          = errors.New("expired")
    41  	errUnsolicitedReply = errors.New("unsolicited reply")
    42  	errUnknownNode      = errors.New("unknown node")
    43  	errTimeout          = errors.New("RPC timeout")
    44  	errClockWarp        = errors.New("reply deadline too far in the future")
    45  	errClosed           = errors.New("socket closed")
    46  )
    47  
    48  // Timeouts
    49  const (
    50  	respTimeout    = 500 * time.Millisecond
    51  	expiration     = 20 * time.Second
    52  	bondExpiration = 24 * time.Hour
    53  
    54  	ntpFailureThreshold = 32               // Continuous timeouts after which to check NTP
    55  	ntpWarningCooldown  = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning
    56  	driftThreshold      = 10 * time.Second // Allowed clock drift before warning user
    57  )
    58  
    59  // RPC packet types
    60  const (
    61  	pingPacket = iota + 1 // zero is 'reserved'
    62  	pongPacket
    63  	findnodePacket
    64  	neighborsPacket
    65  	pingXDC
    66  )
    67  
    68  // RPC request structures
    69  type (
    70  	ping struct {
    71  		senderKey *ecdsa.PublicKey // filled in by preverify
    72  
    73  		Version    uint
    74  		From, To   rpcEndpoint
    75  		Expiration uint64
    76  		// Ignore additional fields (for forward compatibility).
    77  		Rest []rlp.RawValue `rlp:"tail"`
    78  	}
    79  
    80  	// pong is the reply to ping.
    81  	pong struct {
    82  		// This field should mirror the UDP envelope address
    83  		// of the ping packet, which provides a way to discover the
    84  		// the external address (after NAT).
    85  		To rpcEndpoint
    86  
    87  		ReplyTok   []byte // This contains the hash of the ping packet.
    88  		Expiration uint64 // Absolute timestamp at which the packet becomes invalid.
    89  		// Ignore additional fields (for forward compatibility).
    90  		Rest []rlp.RawValue `rlp:"tail"`
    91  	}
    92  
    93  	// findnode is a query for nodes close to the given target.
    94  	findnode struct {
    95  		Target     encPubkey
    96  		Expiration uint64
    97  		// Ignore additional fields (for forward compatibility).
    98  		Rest []rlp.RawValue `rlp:"tail"`
    99  	}
   100  
   101  	// reply to findnode
   102  	neighbors struct {
   103  		Nodes      []rpcNode
   104  		Expiration uint64
   105  		// Ignore additional fields (for forward compatibility).
   106  		Rest []rlp.RawValue `rlp:"tail"`
   107  	}
   108  
   109  	rpcNode struct {
   110  		IP  net.IP // len 4 for IPv4 or 16 for IPv6
   111  		UDP uint16 // for discovery protocol
   112  		TCP uint16 // for RLPx protocol
   113  		ID  encPubkey
   114  	}
   115  
   116  	rpcEndpoint struct {
   117  		IP  net.IP // len 4 for IPv4 or 16 for IPv6
   118  		UDP uint16 // for discovery protocol
   119  		TCP uint16 // for RLPx protocol
   120  	}
   121  )
   122  
   123  func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
   124  	ip := net.IP{}
   125  	if ip4 := addr.IP.To4(); ip4 != nil {
   126  		ip = ip4
   127  	} else if ip6 := addr.IP.To16(); ip6 != nil {
   128  		ip = ip6
   129  	}
   130  	return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
   131  }
   132  
   133  func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*node, error) {
   134  	if rn.UDP <= 1024 {
   135  		return nil, errors.New("low port")
   136  	}
   137  	if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
   138  		return nil, err
   139  	}
   140  	if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) {
   141  		return nil, errors.New("not contained in netrestrict whitelist")
   142  	}
   143  	key, err := decodePubkey(rn.ID)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP)))
   148  	err = n.ValidateComplete()
   149  	return n, err
   150  }
   151  
   152  func nodeToRPC(n *node) rpcNode {
   153  	var key ecdsa.PublicKey
   154  	var ekey encPubkey
   155  	if err := n.Load((*enode.Secp256k1)(&key)); err == nil {
   156  		ekey = encodePubkey(&key)
   157  	}
   158  	return rpcNode{ID: ekey, IP: n.IP(), UDP: uint16(n.UDP()), TCP: uint16(n.TCP())}
   159  }
   160  
   161  // packet is implemented by all protocol messages.
   162  type packet interface {
   163  	// preverify checks whether the packet is valid and should be handled at all.
   164  	preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error
   165  	// handle handles the packet.
   166  	handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte)
   167  	// name returns the name of the packet for logging purposes.
   168  	name() string
   169  }
   170  
   171  type conn interface {
   172  	ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
   173  	WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)
   174  	Close() error
   175  	LocalAddr() net.Addr
   176  }
   177  
   178  // udp implements the discovery v4 UDP wire protocol.
   179  type udp struct {
   180  	conn        conn
   181  	netrestrict *netutil.Netlist
   182  	priv        *ecdsa.PrivateKey
   183  	localNode   *enode.LocalNode
   184  	db          *enode.DB
   185  	tab         *Table
   186  	wg          sync.WaitGroup
   187  
   188  	addReplyMatcher chan *replyMatcher
   189  	gotreply        chan reply
   190  	closing         chan struct{}
   191  }
   192  
   193  // pending represents a pending reply.
   194  //
   195  // Some implementations of the protocol wish to send more than one
   196  // reply packet to findnode. In general, any neighbors packet cannot
   197  // be matched up with a specific findnode packet.
   198  //
   199  // Our implementation handles this by storing a callback function for
   200  // each pending reply. Incoming packets from a node are dispatched
   201  // to all callback functions for that node.
   202  type replyMatcher struct {
   203  	// these fields must match in the reply.
   204  	from  enode.ID
   205  	ip    net.IP
   206  	ptype byte
   207  
   208  	// time when the request must complete
   209  	deadline time.Time
   210  
   211  	// callback is called when a matching reply arrives. If it returns matched == true, the
   212  	// reply was acceptable. The second return value indicates whether the callback should
   213  	// be removed from the pending reply queue. If it returns false, the reply is considered
   214  	// incomplete and the callback will be invoked again for the next matching reply.
   215  	callback replyMatchFunc
   216  
   217  	// errc receives nil when the callback indicates completion or an
   218  	// error if no further reply is received within the timeout.
   219  	errc chan<- error
   220  }
   221  
   222  type replyMatchFunc func(interface{}) (matched bool, requestDone bool)
   223  
   224  type reply struct {
   225  	from  enode.ID
   226  	ip    net.IP
   227  	ptype byte
   228  	data  packet
   229  
   230  	// loop indicates whether there was
   231  	// a matching request by sending on this channel.
   232  	matched chan<- bool
   233  }
   234  
   235  // ReadPacket is sent to the unhandled channel when it could not be processed
   236  type ReadPacket struct {
   237  	Data []byte
   238  	Addr *net.UDPAddr
   239  }
   240  
   241  // Config holds Table-related settings.
   242  type Config struct {
   243  	// These settings are required and configure the UDP listener:
   244  	PrivateKey *ecdsa.PrivateKey
   245  
   246  	// These settings are optional:
   247  	NetRestrict *netutil.Netlist  // network whitelist
   248  	Bootnodes   []*enode.Node     // list of bootstrap nodes
   249  	Unhandled   chan<- ReadPacket // unhandled packets are sent on this channel
   250  }
   251  
   252  // ListenUDP returns a new table that listens for UDP packets on laddr.
   253  func ListenUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, error) {
   254  	tab, _, err := newUDP(c, ln, cfg)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	return tab, nil
   259  }
   260  
   261  func newUDP(c conn, ln *enode.LocalNode, cfg Config) (*Table, *udp, error) {
   262  	udp := &udp{
   263  		conn:            c,
   264  		priv:            cfg.PrivateKey,
   265  		netrestrict:     cfg.NetRestrict,
   266  		localNode:       ln,
   267  		db:              ln.Database(),
   268  		closing:         make(chan struct{}),
   269  		gotreply:        make(chan reply),
   270  		addReplyMatcher: make(chan *replyMatcher),
   271  	}
   272  	tab, err := newTable(udp, ln.Database(), cfg.Bootnodes)
   273  	if err != nil {
   274  		return nil, nil, err
   275  	}
   276  	udp.tab = tab
   277  
   278  	udp.wg.Add(2)
   279  	go udp.loop()
   280  	go udp.readLoop(cfg.Unhandled)
   281  	return udp.tab, udp, nil
   282  }
   283  
   284  func (t *udp) self() *enode.Node {
   285  	return t.localNode.Node()
   286  }
   287  
   288  func (t *udp) close() {
   289  	close(t.closing)
   290  	t.conn.Close()
   291  	t.wg.Wait()
   292  }
   293  
   294  func (t *udp) ourEndpoint() rpcEndpoint {
   295  	n := t.self()
   296  	a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()}
   297  	return makeEndpoint(a, uint16(n.TCP()))
   298  }
   299  
   300  // ping sends a ping message to the given node and waits for a reply.
   301  func (t *udp) ping(toid enode.ID, toaddr *net.UDPAddr) error {
   302  	return <-t.sendPing(toid, toaddr, nil)
   303  }
   304  
   305  // sendPing sends a ping message to the given node and invokes the callback
   306  // when the reply arrives.
   307  func (t *udp) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) <-chan error {
   308  	req := &ping{
   309  		Version:    4,
   310  		From:       t.ourEndpoint(),
   311  		To:         makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB
   312  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   313  	}
   314  	packet, hash, err := encodePacket(t.priv, pingXDC, req)
   315  	if err != nil {
   316  		errc := make(chan error, 1)
   317  		errc <- err
   318  		return errc
   319  	}
   320  	// Add a matcher for the reply to the pending reply queue. Pongs are matched if they
   321  	// reference the ping we're about to send.
   322  	errc := t.pending(toid, toaddr.IP, pongPacket, func(p interface{}) (matched bool, requestDone bool) {
   323  		matched = bytes.Equal(p.(*pong).ReplyTok, hash)
   324  		if matched && callback != nil {
   325  			callback()
   326  		}
   327  		return matched, matched
   328  	})
   329  	// Send the packet.
   330  	t.localNode.UDPContact(toaddr)
   331  	t.write(toaddr, toid, req.name(), packet)
   332  	return errc
   333  }
   334  
   335  // findnode sends a findnode request to the given node and waits until
   336  // the node has sent up to k neighbors.
   337  func (t *udp) findnode(toid enode.ID, toaddr *net.UDPAddr, target encPubkey) ([]*node, error) {
   338  	// If we haven't seen a ping from the destination node for a while, it won't remember
   339  	// our endpoint proof and reject findnode. Solicit a ping first.
   340  	if time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration {
   341  		t.ping(toid, toaddr)
   342  		// Wait for them to ping back and process our pong.
   343  		time.Sleep(respTimeout)
   344  	}
   345  
   346  	// Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is
   347  	// active until enough nodes have been received.
   348  	nodes := make([]*node, 0, bucketSize)
   349  	nreceived := 0
   350  	errc := t.pending(toid, toaddr.IP, neighborsPacket, func(r interface{}) (matched bool, requestDone bool) {
   351  		reply := r.(*neighbors)
   352  		for _, rn := range reply.Nodes {
   353  			nreceived++
   354  			n, err := t.nodeFromRPC(toaddr, rn)
   355  			if err != nil {
   356  				log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
   357  				continue
   358  			}
   359  			nodes = append(nodes, n)
   360  		}
   361  		return true, nreceived >= bucketSize
   362  	})
   363  	t.send(toaddr, toid, findnodePacket, &findnode{
   364  		Target:     target,
   365  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   366  	})
   367  	return nodes, <-errc
   368  }
   369  
   370  // pending adds a reply matcher to the pending reply queue.
   371  // see the documentation of type replyMatcher for a detailed explanation.
   372  func (t *udp) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) <-chan error {
   373  	ch := make(chan error, 1)
   374  	p := &replyMatcher{from: id, ip: ip, ptype: ptype, callback: callback, errc: ch}
   375  	select {
   376  	case t.addReplyMatcher <- p:
   377  		// loop will handle it
   378  	case <-t.closing:
   379  		ch <- errClosed
   380  	}
   381  	return ch
   382  }
   383  
   384  // handleReply dispatches a reply packet, invoking reply matchers. It returns
   385  // whether any matcher considered the packet acceptable.
   386  func (t *udp) handleReply(from enode.ID, fromIP net.IP, ptype byte, req packet) bool {
   387  	matched := make(chan bool, 1)
   388  	select {
   389  	case t.gotreply <- reply{from, fromIP, ptype, req, matched}:
   390  		// loop will handle it
   391  		return <-matched
   392  	case <-t.closing:
   393  		return false
   394  	}
   395  }
   396  
   397  // loop runs in its own goroutine. it keeps track of
   398  // the refresh timer and the pending reply queue.
   399  func (t *udp) loop() {
   400  	defer t.wg.Done()
   401  
   402  	var (
   403  		plist        = list.New()
   404  		timeout      = time.NewTimer(0)
   405  		nextTimeout  *replyMatcher // head of plist when timeout was last reset
   406  		contTimeouts = 0           // number of continuous timeouts to do NTP checks
   407  		ntpWarnTime  = time.Unix(0, 0)
   408  	)
   409  	<-timeout.C // ignore first timeout
   410  	defer timeout.Stop()
   411  
   412  	resetTimeout := func() {
   413  		if plist.Front() == nil || nextTimeout == plist.Front().Value {
   414  			return
   415  		}
   416  		// Start the timer so it fires when the next pending reply has expired.
   417  		now := time.Now()
   418  		for el := plist.Front(); el != nil; el = el.Next() {
   419  			nextTimeout = el.Value.(*replyMatcher)
   420  			if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout {
   421  				timeout.Reset(dist)
   422  				return
   423  			}
   424  			// Remove pending replies whose deadline is too far in the
   425  			// future. These can occur if the system clock jumped
   426  			// backwards after the deadline was assigned.
   427  			nextTimeout.errc <- errClockWarp
   428  			plist.Remove(el)
   429  		}
   430  		nextTimeout = nil
   431  		timeout.Stop()
   432  	}
   433  
   434  	for {
   435  		resetTimeout()
   436  
   437  		select {
   438  		case <-t.closing:
   439  			for el := plist.Front(); el != nil; el = el.Next() {
   440  				el.Value.(*replyMatcher).errc <- errClosed
   441  			}
   442  			return
   443  
   444  		case p := <-t.addReplyMatcher:
   445  			p.deadline = time.Now().Add(respTimeout)
   446  			plist.PushBack(p)
   447  
   448  		case r := <-t.gotreply:
   449  			var matched bool // whether any replyMatcher considered the reply acceptable.
   450  			for el := plist.Front(); el != nil; el = el.Next() {
   451  				p := el.Value.(*replyMatcher)
   452  				if p.from == r.from && p.ptype == r.ptype && p.ip.Equal(r.ip) {
   453  					ok, requestDone := p.callback(r.data)
   454  					matched = matched || ok
   455  					// Remove the matcher if callback indicates that all replies have been received.
   456  					if requestDone {
   457  						p.errc <- nil
   458  						plist.Remove(el)
   459  					}
   460  					// Reset the continuous timeout counter (time drift detection)
   461  					contTimeouts = 0
   462  				}
   463  			}
   464  			r.matched <- matched
   465  
   466  		case now := <-timeout.C:
   467  			nextTimeout = nil
   468  
   469  			// Notify and remove callbacks whose deadline is in the past.
   470  			for el := plist.Front(); el != nil; el = el.Next() {
   471  				p := el.Value.(*replyMatcher)
   472  				if now.After(p.deadline) || now.Equal(p.deadline) {
   473  					p.errc <- errTimeout
   474  					plist.Remove(el)
   475  					contTimeouts++
   476  				}
   477  			}
   478  			// If we've accumulated too many timeouts, do an NTP time sync check
   479  			if contTimeouts > ntpFailureThreshold {
   480  				if time.Since(ntpWarnTime) >= ntpWarningCooldown {
   481  					ntpWarnTime = time.Now()
   482  					go checkClockDrift()
   483  				}
   484  				contTimeouts = 0
   485  			}
   486  		}
   487  	}
   488  }
   489  
   490  const (
   491  	macSize  = 256 / 8
   492  	sigSize  = 520 / 8
   493  	headSize = macSize + sigSize // space of packet frame data
   494  )
   495  
   496  var (
   497  	headSpace = make([]byte, headSize)
   498  
   499  	// Neighbors replies are sent across multiple packets to
   500  	// stay below the 1280 byte limit. We compute the maximum number
   501  	// of entries by stuffing a packet until it grows too large.
   502  	maxNeighbors int
   503  )
   504  
   505  func init() {
   506  	p := neighbors{Expiration: ^uint64(0)}
   507  	maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   508  	for n := 0; ; n++ {
   509  		p.Nodes = append(p.Nodes, maxSizeNode)
   510  		size, _, err := rlp.EncodeToReader(p)
   511  		if err != nil {
   512  			// If this ever happens, it will be caught by the unit tests.
   513  			panic("cannot encode: " + err.Error())
   514  		}
   515  		if headSize+size+1 >= 1280 {
   516  			maxNeighbors = n
   517  			break
   518  		}
   519  	}
   520  }
   521  
   522  func (t *udp) send(toaddr *net.UDPAddr, toid enode.ID, ptype byte, req packet) ([]byte, error) {
   523  	packet, hash, err := encodePacket(t.priv, ptype, req)
   524  	if err != nil {
   525  		return hash, err
   526  	}
   527  	return hash, t.write(toaddr, toid, req.name(), packet)
   528  }
   529  
   530  func (t *udp) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error {
   531  	_, err := t.conn.WriteToUDP(packet, toaddr)
   532  	log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err)
   533  	return err
   534  }
   535  
   536  func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) {
   537  	b := new(bytes.Buffer)
   538  	b.Write(headSpace)
   539  	b.WriteByte(ptype)
   540  	if err := rlp.Encode(b, req); err != nil {
   541  		log.Error("Can't encode discv4 packet", "err", err)
   542  		return nil, nil, err
   543  	}
   544  	packet = b.Bytes()
   545  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   546  	if err != nil {
   547  		log.Error("Can't sign discv4 packet", "err", err)
   548  		return nil, nil, err
   549  	}
   550  	copy(packet[macSize:], sig)
   551  	// add the hash to the front. Note: this doesn't protect the
   552  	// packet in any way. Our public key will be part of this hash in
   553  	// The future.
   554  	hash = crypto.Keccak256(packet[macSize:])
   555  	copy(packet, hash)
   556  	return packet, hash, nil
   557  }
   558  
   559  // readLoop runs in its own goroutine. it handles incoming UDP packets.
   560  func (t *udp) readLoop(unhandled chan<- ReadPacket) {
   561  	defer t.wg.Done()
   562  	if unhandled != nil {
   563  		defer close(unhandled)
   564  	}
   565  
   566  	// Discovery packets are defined to be no larger than 1280 bytes.
   567  	// Packets larger than this size will be cut at the end and treated
   568  	// as invalid because their hash won't match.
   569  	buf := make([]byte, 1280)
   570  	for {
   571  		nbytes, from, err := t.conn.ReadFromUDP(buf)
   572  		if netutil.IsTemporaryError(err) {
   573  			// Ignore temporary read errors.
   574  			log.Debug("Temporary UDP read error", "err", err)
   575  			continue
   576  		} else if err != nil {
   577  			// Shut down the loop for permament errors.
   578  			log.Debug("UDP read error", "err", err)
   579  			return
   580  		}
   581  		if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil {
   582  			select {
   583  			case unhandled <- ReadPacket{buf[:nbytes], from}:
   584  			default:
   585  			}
   586  		}
   587  	}
   588  }
   589  
   590  func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
   591  	packet, fromKey, hash, err := decodePacket(buf)
   592  	if err != nil {
   593  		log.Debug("Bad discv4 packet", "addr", from, "err", err)
   594  		return err
   595  	}
   596  	fromID := fromKey.id()
   597  	if err == nil {
   598  		err = packet.preverify(t, from, fromID, fromKey)
   599  	}
   600  	log.Trace("<< "+packet.name(), "id", fromID, "addr", from, "err", err)
   601  	if err == nil {
   602  		packet.handle(t, from, fromID, hash)
   603  	}
   604  	return err
   605  }
   606  
   607  func decodePacket(buf []byte) (packet, encPubkey, []byte, error) {
   608  	if len(buf) < headSize+1 {
   609  		return nil, encPubkey{}, nil, errPacketTooSmall
   610  	}
   611  	hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
   612  	shouldhash := crypto.Keccak256(buf[macSize:])
   613  	if !bytes.Equal(hash, shouldhash) {
   614  		return nil, encPubkey{}, nil, errBadHash
   615  	}
   616  	fromKey, err := recoverNodeKey(crypto.Keccak256(buf[headSize:]), sig)
   617  	if err != nil {
   618  		return nil, fromKey, hash, err
   619  	}
   620  
   621  	var req packet
   622  	switch ptype := sigdata[0]; ptype {
   623  	case pingXDC:
   624  		req = new(ping)
   625  	case pongPacket:
   626  		req = new(pong)
   627  	case findnodePacket:
   628  		req = new(findnode)
   629  	case neighborsPacket:
   630  		req = new(neighbors)
   631  	default:
   632  		return nil, fromKey, hash, fmt.Errorf("unknown type: %d", ptype)
   633  	}
   634  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   635  	err = s.Decode(req)
   636  	return req, fromKey, hash, err
   637  }
   638  
   639  // Packet Handlers
   640  
   641  func (req *ping) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error {
   642  	if expired(req.Expiration) {
   643  		return errExpired
   644  	}
   645  	key, err := decodePubkey(fromKey)
   646  	if err != nil {
   647  		return errors.New("invalid public key")
   648  	}
   649  	req.senderKey = key
   650  	return nil
   651  }
   652  
   653  func (req *ping) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) {
   654  	// Reply.
   655  	t.send(from, fromID, pongPacket, &pong{
   656  		To:         makeEndpoint(from, req.From.TCP),
   657  		ReplyTok:   mac,
   658  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   659  	})
   660  
   661  	// Ping back if our last pong on file is too far in the past.
   662  	n := wrapNode(enode.NewV4(req.senderKey, from.IP, int(req.From.TCP), from.Port))
   663  	if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration {
   664  		t.sendPing(fromID, from, func() {
   665  			t.tab.addVerifiedNode(n)
   666  		})
   667  	} else {
   668  		t.tab.addVerifiedNode(n)
   669  	}
   670  
   671  	// Update node database and endpoint predictor.
   672  	t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now())
   673  	t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)})
   674  }
   675  
   676  func (req *ping) name() string { return "PING XDC/v4" }
   677  
   678  func (req *pong) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error {
   679  	if expired(req.Expiration) {
   680  		return errExpired
   681  	}
   682  	if !t.handleReply(fromID, from.IP, pongPacket, req) {
   683  		return errUnsolicitedReply
   684  	}
   685  	return nil
   686  }
   687  
   688  func (req *pong) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) {
   689  	t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)})
   690  	t.db.UpdateLastPongReceived(fromID, from.IP, time.Now())
   691  }
   692  
   693  func (req *pong) name() string { return "PONG/v4" }
   694  
   695  func (req *findnode) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error {
   696  	if expired(req.Expiration) {
   697  		return errExpired
   698  	}
   699  	if time.Since(t.db.LastPongReceived(fromID, from.IP)) > bondExpiration {
   700  		// No endpoint proof pong exists, we don't process the packet. This prevents an
   701  		// attack vector where the discovery protocol could be used to amplify traffic in a
   702  		// DDOS attack. A malicious actor would send a findnode request with the IP address
   703  		// and UDP port of the target as the source address. The recipient of the findnode
   704  		// packet would then send a neighbors packet (which is a much bigger packet than
   705  		// findnode) to the victim.
   706  		return errUnknownNode
   707  	}
   708  	return nil
   709  }
   710  
   711  func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) {
   712  	// Determine closest nodes.
   713  	target := enode.ID(crypto.Keccak256Hash(req.Target[:]))
   714  	t.tab.mutex.Lock()
   715  	closest := t.tab.closest(target, bucketSize).entries
   716  	t.tab.mutex.Unlock()
   717  	log.Trace("find neighbors ", "from", from, "fromID", fromID, "closest", len(closest))
   718  
   719  	// Send neighbors in chunks with at most maxNeighbors per packet
   720  	// to stay below the 1280 byte limit.
   721  	p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())}
   722  	var sent bool
   723  	for _, n := range closest {
   724  		if netutil.CheckRelayIP(from.IP, n.IP()) == nil {
   725  			p.Nodes = append(p.Nodes, nodeToRPC(n))
   726  		}
   727  		if len(p.Nodes) == maxNeighbors {
   728  			t.send(from, fromID, neighborsPacket, &p)
   729  			p.Nodes = p.Nodes[:0]
   730  			sent = true
   731  		}
   732  	}
   733  	if len(p.Nodes) > 0 || !sent {
   734  		t.send(from, fromID, neighborsPacket, &p)
   735  	}
   736  }
   737  
   738  func (req *findnode) name() string { return "FINDNODE/v4" }
   739  
   740  func (req *neighbors) preverify(t *udp, from *net.UDPAddr, fromID enode.ID, fromKey encPubkey) error {
   741  	if expired(req.Expiration) {
   742  		return errExpired
   743  	}
   744  	if !t.handleReply(fromID, from.IP, neighborsPacket, req) {
   745  		return errUnsolicitedReply
   746  	}
   747  	return nil
   748  }
   749  
   750  func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID enode.ID, mac []byte) {
   751  }
   752  
   753  func (req *neighbors) name() string { return "NEIGHBORS/v4" }
   754  
   755  func expired(ts uint64) bool {
   756  	return time.Unix(int64(ts), 0).Before(time.Now())
   757  }