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