github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discover/udp.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:43</date>
    10  //</624342656343871488>
    11  
    12  
    13  package discover
    14  
    15  import (
    16  	"bytes"
    17  	"container/list"
    18  	"crypto/ecdsa"
    19  	"errors"
    20  	"fmt"
    21  	"net"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/crypto"
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/p2p/nat"
    27  	"github.com/ethereum/go-ethereum/p2p/netutil"
    28  	"github.com/ethereum/go-ethereum/rlp"
    29  )
    30  
    31  //错误
    32  var (
    33  	errPacketTooSmall   = errors.New("too small")
    34  	errBadHash          = errors.New("bad hash")
    35  	errExpired          = errors.New("expired")
    36  	errUnsolicitedReply = errors.New("unsolicited reply")
    37  	errUnknownNode      = errors.New("unknown node")
    38  	errTimeout          = errors.New("RPC timeout")
    39  	errClockWarp        = errors.New("reply deadline too far in the future")
    40  	errClosed           = errors.New("socket closed")
    41  )
    42  
    43  //超时
    44  const (
    45  	respTimeout = 500 * time.Millisecond
    46  	expiration  = 20 * time.Second
    47  
    48  ntpFailureThreshold = 32               //连续超时,之后检查NTP
    49  ntpWarningCooldown  = 10 * time.Minute //重复NTP警告之前要经过的最短时间
    50  driftThreshold      = 10 * time.Second //警告用户前允许的时钟漂移
    51  )
    52  
    53  //RPC数据包类型
    54  const (
    55  pingPacket = iota + 1 //零为“保留”
    56  	pongPacket
    57  	findnodePacket
    58  	neighborsPacket
    59  )
    60  
    61  //RPC请求结构
    62  type (
    63  	ping struct {
    64  		Version    uint
    65  		From, To   rpcEndpoint
    66  		Expiration uint64
    67  //忽略其他字段(为了向前兼容)。
    68  		Rest []rlp.RawValue `rlp:"tail"`
    69  	}
    70  
    71  //乒乓球是对乒乓球的回应。
    72  	pong struct {
    73  //此字段应镜像UDP信封地址
    74  //提供了一种发现
    75  //外部地址(在NAT之后)。
    76  		To rpcEndpoint
    77  
    78  ReplyTok   []byte //这包含ping包的哈希。
    79  Expiration uint64 //数据包失效的绝对时间戳。
    80  //忽略其他字段(为了向前兼容)。
    81  		Rest []rlp.RawValue `rlp:"tail"`
    82  	}
    83  
    84  //findnode是对接近给定目标的节点的查询。
    85  	findnode struct {
    86  Target     NodeID //不需要是实际的公钥
    87  		Expiration uint64
    88  //忽略其他字段(为了向前兼容)。
    89  		Rest []rlp.RawValue `rlp:"tail"`
    90  	}
    91  
    92  //回复findnode
    93  	neighbors struct {
    94  		Nodes      []rpcNode
    95  		Expiration uint64
    96  //忽略其他字段(为了向前兼容)。
    97  		Rest []rlp.RawValue `rlp:"tail"`
    98  	}
    99  
   100  	rpcNode struct {
   101  IP  net.IP //IPv4的len 4或IPv6的len 16
   102  UDP uint16 //用于发现协议
   103  TCP uint16 //对于RLPX协议
   104  		ID  NodeID
   105  	}
   106  
   107  	rpcEndpoint struct {
   108  IP  net.IP //IPv4的len 4或IPv6的len 16
   109  UDP uint16 //用于发现协议
   110  TCP uint16 //对于RLPX协议
   111  	}
   112  )
   113  
   114  func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
   115  	ip := addr.IP.To4()
   116  	if ip == nil {
   117  		ip = addr.IP.To16()
   118  	}
   119  	return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
   120  }
   121  
   122  func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) {
   123  	if rn.UDP <= 1024 {
   124  		return nil, errors.New("low port")
   125  	}
   126  	if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
   127  		return nil, err
   128  	}
   129  	if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) {
   130  		return nil, errors.New("not contained in netrestrict whitelist")
   131  	}
   132  	n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP)
   133  	err := n.validateComplete()
   134  	return n, err
   135  }
   136  
   137  func nodeToRPC(n *Node) rpcNode {
   138  	return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP}
   139  }
   140  
   141  type packet interface {
   142  	handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error
   143  	name() string
   144  }
   145  
   146  type conn interface {
   147  	ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error)
   148  	WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error)
   149  	Close() error
   150  	LocalAddr() net.Addr
   151  }
   152  
   153  //UDP实现RPC协议。
   154  type udp struct {
   155  	conn        conn
   156  	netrestrict *netutil.Netlist
   157  	priv        *ecdsa.PrivateKey
   158  	ourEndpoint rpcEndpoint
   159  
   160  	addpending chan *pending
   161  	gotreply   chan reply
   162  
   163  	closing chan struct{}
   164  	nat     nat.Interface
   165  
   166  	*Table
   167  }
   168  
   169  //挂起表示挂起的答复。
   170  //
   171  //协议的某些实现希望发送多个
   172  //将数据包回复到findnode。一般来说,任何邻居包都不能
   173  //与特定的findnode包匹配。
   174  //
   175  //我们的实现通过存储
   176  //每个等待答复。来自节点的传入数据包被调度
   177  //到该节点的所有回调函数。
   178  type pending struct {
   179  //这些字段必须在答复中匹配。
   180  	from  NodeID
   181  	ptype byte
   182  
   183  //请求必须完成的时间
   184  	deadline time.Time
   185  
   186  //当匹配的答复到达时调用回调。如果它回来
   187  //如果为true,则从挂起的答复队列中删除回调。
   188  //如果返回错误,则认为答复不完整,并且
   189  //将为下一个匹配的答复再次调用回调。
   190  	callback func(resp interface{}) (done bool)
   191  
   192  //当回调指示完成或
   193  //如果在超时时间内没有收到进一步的答复,则出错。
   194  	errc chan<- error
   195  }
   196  
   197  type reply struct {
   198  	from  NodeID
   199  	ptype byte
   200  	data  interface{}
   201  //循环指示是否存在
   202  //通过此频道发送的匹配请求。
   203  	matched chan<- bool
   204  }
   205  
   206  //无法处理readpacket时,会将其发送到未处理的通道。
   207  type ReadPacket struct {
   208  	Data []byte
   209  	Addr *net.UDPAddr
   210  }
   211  
   212  //配置保存与表相关的设置。
   213  type Config struct {
   214  //需要这些设置并配置UDP侦听器:
   215  	PrivateKey *ecdsa.PrivateKey
   216  
   217  //这些设置是可选的:
   218  AnnounceAddr *net.UDPAddr      //DHT中公布的本地地址
   219  NodeDBPath   string            //如果设置,则节点数据库存储在此文件系统位置
   220  NetRestrict  *netutil.Netlist  //网络白名单
   221  Bootnodes    []*Node           //引导程序节点列表
   222  Unhandled    chan<- ReadPacket //在此通道上发送未处理的数据包
   223  }
   224  
   225  //listenudp返回一个新表,用于侦听laddr上的udp包。
   226  func ListenUDP(c conn, cfg Config) (*Table, error) {
   227  	tab, _, err := newUDP(c, cfg)
   228  	if err != nil {
   229  		return nil, err
   230  	}
   231  	log.Info("UDP listener up", "self", tab.self)
   232  	return tab, nil
   233  }
   234  
   235  func newUDP(c conn, cfg Config) (*Table, *udp, error) {
   236  	udp := &udp{
   237  		conn:        c,
   238  		priv:        cfg.PrivateKey,
   239  		netrestrict: cfg.NetRestrict,
   240  		closing:     make(chan struct{}),
   241  		gotreply:    make(chan reply),
   242  		addpending:  make(chan *pending),
   243  	}
   244  	realaddr := c.LocalAddr().(*net.UDPAddr)
   245  	if cfg.AnnounceAddr != nil {
   246  		realaddr = cfg.AnnounceAddr
   247  	}
   248  //TODO:单独的TCP端口
   249  	udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port))
   250  	tab, err := newTable(udp, PubkeyID(&cfg.PrivateKey.PublicKey), realaddr, cfg.NodeDBPath, cfg.Bootnodes)
   251  	if err != nil {
   252  		return nil, nil, err
   253  	}
   254  	udp.Table = tab
   255  
   256  	go udp.loop()
   257  	go udp.readLoop(cfg.Unhandled)
   258  	return udp.Table, udp, nil
   259  }
   260  
   261  func (t *udp) close() {
   262  	close(t.closing)
   263  	t.conn.Close()
   264  //TODO:等待循环结束。
   265  }
   266  
   267  //ping向给定节点发送ping消息并等待答复。
   268  func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error {
   269  	return <-t.sendPing(toid, toaddr, nil)
   270  }
   271  
   272  //发送ping向给定节点发送ping消息并调用回调
   273  //当回复到达时。
   274  func (t *udp) sendPing(toid NodeID, toaddr *net.UDPAddr, callback func()) <-chan error {
   275  	req := &ping{
   276  		Version:    4,
   277  		From:       t.ourEndpoint,
   278  To:         makeEndpoint(toaddr, 0), //TODO:可能使用数据库中已知的TCP端口
   279  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   280  	}
   281  	packet, hash, err := encodePacket(t.priv, pingPacket, req)
   282  	if err != nil {
   283  		errc := make(chan error, 1)
   284  		errc <- err
   285  		return errc
   286  	}
   287  	errc := t.pending(toid, pongPacket, func(p interface{}) bool {
   288  		ok := bytes.Equal(p.(*pong).ReplyTok, hash)
   289  		if ok && callback != nil {
   290  			callback()
   291  		}
   292  		return ok
   293  	})
   294  	t.write(toaddr, req.name(), packet)
   295  	return errc
   296  }
   297  
   298  func (t *udp) waitping(from NodeID) error {
   299  	return <-t.pending(from, pingPacket, func(interface{}) bool { return true })
   300  }
   301  
   302  //findnode向给定节点发送findnode请求,并等待直到
   303  //节点已发送到k个邻居。
   304  func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
   305  //如果我们有一段时间没有看到目标节点的ping,它将不会记得
   306  //我们的端点证明和拒绝findnode。先打个乒乓球。
   307  	if time.Since(t.db.lastPingReceived(toid)) > nodeDBNodeExpiration {
   308  		t.ping(toid, toaddr)
   309  		t.waitping(toid)
   310  	}
   311  
   312  	nodes := make([]*Node, 0, bucketSize)
   313  	nreceived := 0
   314  	errc := t.pending(toid, neighborsPacket, func(r interface{}) bool {
   315  		reply := r.(*neighbors)
   316  		for _, rn := range reply.Nodes {
   317  			nreceived++
   318  			n, err := t.nodeFromRPC(toaddr, rn)
   319  			if err != nil {
   320  				log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err)
   321  				continue
   322  			}
   323  			nodes = append(nodes, n)
   324  		}
   325  		return nreceived >= bucketSize
   326  	})
   327  	t.send(toaddr, findnodePacket, &findnode{
   328  		Target:     target,
   329  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   330  	})
   331  	return nodes, <-errc
   332  }
   333  
   334  //挂起向挂起的答复队列添加答复回调。
   335  //有关详细说明,请参阅“挂起”类型的文档。
   336  func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-chan error {
   337  	ch := make(chan error, 1)
   338  	p := &pending{from: id, ptype: ptype, callback: callback, errc: ch}
   339  	select {
   340  	case t.addpending <- p:
   341  //循环将处理它
   342  	case <-t.closing:
   343  		ch <- errClosed
   344  	}
   345  	return ch
   346  }
   347  
   348  func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool {
   349  	matched := make(chan bool, 1)
   350  	select {
   351  	case t.gotreply <- reply{from, ptype, req, matched}:
   352  //循环将处理它
   353  		return <-matched
   354  	case <-t.closing:
   355  		return false
   356  	}
   357  }
   358  
   359  //循环在自己的Goroutine中运行。它跟踪
   360  //刷新计时器和挂起的答复队列。
   361  func (t *udp) loop() {
   362  	var (
   363  		plist        = list.New()
   364  		timeout      = time.NewTimer(0)
   365  nextTimeout  *pending //上次重置超时时的plist头
   366  contTimeouts = 0      //要执行NTP检查的连续超时数
   367  		ntpWarnTime  = time.Unix(0, 0)
   368  	)
   369  <-timeout.C //忽略第一次超时
   370  	defer timeout.Stop()
   371  
   372  	resetTimeout := func() {
   373  		if plist.Front() == nil || nextTimeout == plist.Front().Value {
   374  			return
   375  		}
   376  //启动计时器,以便在下一个挂起的答复过期时触发。
   377  		now := time.Now()
   378  		for el := plist.Front(); el != nil; el = el.Next() {
   379  			nextTimeout = el.Value.(*pending)
   380  			if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout {
   381  				timeout.Reset(dist)
   382  				return
   383  			}
   384  //删除截止时间太长的挂起答复
   385  //未来。如果系统时钟跳变,就会发生这种情况。
   386  //在最后期限被分配后向后。
   387  			nextTimeout.errc <- errClockWarp
   388  			plist.Remove(el)
   389  		}
   390  		nextTimeout = nil
   391  		timeout.Stop()
   392  	}
   393  
   394  	for {
   395  		resetTimeout()
   396  
   397  		select {
   398  		case <-t.closing:
   399  			for el := plist.Front(); el != nil; el = el.Next() {
   400  				el.Value.(*pending).errc <- errClosed
   401  			}
   402  			return
   403  
   404  		case p := <-t.addpending:
   405  			p.deadline = time.Now().Add(respTimeout)
   406  			plist.PushBack(p)
   407  
   408  		case r := <-t.gotreply:
   409  			var matched bool
   410  			for el := plist.Front(); el != nil; el = el.Next() {
   411  				p := el.Value.(*pending)
   412  				if p.from == r.from && p.ptype == r.ptype {
   413  					matched = true
   414  //如果Matcher的回调指示
   415  //所有答复都已收到。这是
   416  //需要多个数据包类型
   417  //应答包。
   418  					if p.callback(r.data) {
   419  						p.errc <- nil
   420  						plist.Remove(el)
   421  					}
   422  //重置连续超时计数器(时间漂移检测)
   423  					contTimeouts = 0
   424  				}
   425  			}
   426  			r.matched <- matched
   427  
   428  		case now := <-timeout.C:
   429  			nextTimeout = nil
   430  
   431  //通知并删除期限已过的回调。
   432  			for el := plist.Front(); el != nil; el = el.Next() {
   433  				p := el.Value.(*pending)
   434  				if now.After(p.deadline) || now.Equal(p.deadline) {
   435  					p.errc <- errTimeout
   436  					plist.Remove(el)
   437  					contTimeouts++
   438  				}
   439  			}
   440  //如果我们累积了太多超时,请执行NTP时间同步检查
   441  			if contTimeouts > ntpFailureThreshold {
   442  				if time.Since(ntpWarnTime) >= ntpWarningCooldown {
   443  					ntpWarnTime = time.Now()
   444  					go checkClockDrift()
   445  				}
   446  				contTimeouts = 0
   447  			}
   448  		}
   449  	}
   450  }
   451  
   452  const (
   453  	macSize  = 256 / 8
   454  	sigSize  = 520 / 8
   455  headSize = macSize + sigSize //包帧数据空间
   456  )
   457  
   458  var (
   459  	headSpace = make([]byte, headSize)
   460  
   461  //邻居答复通过多个数据包发送到
   462  //低于1280字节的限制。我们计算最大数
   463  //通过填充一个包直到它变得太大。
   464  	maxNeighbors int
   465  )
   466  
   467  func init() {
   468  	p := neighbors{Expiration: ^uint64(0)}
   469  	maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)}
   470  	for n := 0; ; n++ {
   471  		p.Nodes = append(p.Nodes, maxSizeNode)
   472  		size, _, err := rlp.EncodeToReader(p)
   473  		if err != nil {
   474  //如果发生这种情况,它将被单元测试捕获。
   475  			panic("cannot encode: " + err.Error())
   476  		}
   477  		if headSize+size+1 >= 1280 {
   478  			maxNeighbors = n
   479  			break
   480  		}
   481  	}
   482  }
   483  
   484  func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) {
   485  	packet, hash, err := encodePacket(t.priv, ptype, req)
   486  	if err != nil {
   487  		return hash, err
   488  	}
   489  	return hash, t.write(toaddr, req.name(), packet)
   490  }
   491  
   492  func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error {
   493  	_, err := t.conn.WriteToUDP(packet, toaddr)
   494  	log.Trace(">> "+what, "addr", toaddr, "err", err)
   495  	return err
   496  }
   497  
   498  func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) {
   499  	b := new(bytes.Buffer)
   500  	b.Write(headSpace)
   501  	b.WriteByte(ptype)
   502  	if err := rlp.Encode(b, req); err != nil {
   503  		log.Error("Can't encode discv4 packet", "err", err)
   504  		return nil, nil, err
   505  	}
   506  	packet = b.Bytes()
   507  	sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv)
   508  	if err != nil {
   509  		log.Error("Can't sign discv4 packet", "err", err)
   510  		return nil, nil, err
   511  	}
   512  	copy(packet[macSize:], sig)
   513  //将哈希添加到前面。注意:这不保护
   514  //以任何方式打包。我们的公钥将是这个哈希的一部分
   515  //未来。
   516  	hash = crypto.Keccak256(packet[macSize:])
   517  	copy(packet, hash)
   518  	return packet, hash, nil
   519  }
   520  
   521  //readloop在自己的goroutine中运行。它处理传入的UDP数据包。
   522  func (t *udp) readLoop(unhandled chan<- ReadPacket) {
   523  	defer t.conn.Close()
   524  	if unhandled != nil {
   525  		defer close(unhandled)
   526  	}
   527  //发现数据包被定义为不大于1280字节。
   528  //大于此尺寸的包装将在末端切割并处理
   529  //因为它们的哈希不匹配而无效。
   530  	buf := make([]byte, 1280)
   531  	for {
   532  		nbytes, from, err := t.conn.ReadFromUDP(buf)
   533  		if netutil.IsTemporaryError(err) {
   534  //忽略临时读取错误。
   535  			log.Debug("Temporary UDP read error", "err", err)
   536  			continue
   537  		} else if err != nil {
   538  //关闭永久错误循环。
   539  			log.Debug("UDP read error", "err", err)
   540  			return
   541  		}
   542  		if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil {
   543  			select {
   544  			case unhandled <- ReadPacket{buf[:nbytes], from}:
   545  			default:
   546  			}
   547  		}
   548  	}
   549  }
   550  
   551  func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error {
   552  	packet, fromID, hash, err := decodePacket(buf)
   553  	if err != nil {
   554  		log.Debug("Bad discv4 packet", "addr", from, "err", err)
   555  		return err
   556  	}
   557  	err = packet.handle(t, from, fromID, hash)
   558  	log.Trace("<< "+packet.name(), "addr", from, "err", err)
   559  	return err
   560  }
   561  
   562  func decodePacket(buf []byte) (packet, NodeID, []byte, error) {
   563  	if len(buf) < headSize+1 {
   564  		return nil, NodeID{}, nil, errPacketTooSmall
   565  	}
   566  	hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:]
   567  	shouldhash := crypto.Keccak256(buf[macSize:])
   568  	if !bytes.Equal(hash, shouldhash) {
   569  		return nil, NodeID{}, nil, errBadHash
   570  	}
   571  	fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig)
   572  	if err != nil {
   573  		return nil, NodeID{}, hash, err
   574  	}
   575  	var req packet
   576  	switch ptype := sigdata[0]; ptype {
   577  	case pingPacket:
   578  		req = new(ping)
   579  	case pongPacket:
   580  		req = new(pong)
   581  	case findnodePacket:
   582  		req = new(findnode)
   583  	case neighborsPacket:
   584  		req = new(neighbors)
   585  	default:
   586  		return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype)
   587  	}
   588  	s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0)
   589  	err = s.Decode(req)
   590  	return req, fromID, hash, err
   591  }
   592  
   593  func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   594  	if expired(req.Expiration) {
   595  		return errExpired
   596  	}
   597  	t.send(from, pongPacket, &pong{
   598  		To:         makeEndpoint(from, req.From.TCP),
   599  		ReplyTok:   mac,
   600  		Expiration: uint64(time.Now().Add(expiration).Unix()),
   601  	})
   602  	t.handleReply(fromID, pingPacket, req)
   603  
   604  //将节点添加到表中。在这样做之前,确保我们最近有足够的乒乓球
   605  //记录在数据库中,以便稍后接受其findnode请求。
   606  	n := NewNode(fromID, from.IP, uint16(from.Port), req.From.TCP)
   607  	if time.Since(t.db.lastPongReceived(fromID)) > nodeDBNodeExpiration {
   608  		t.sendPing(fromID, from, func() { t.addThroughPing(n) })
   609  	} else {
   610  		t.addThroughPing(n)
   611  	}
   612  	t.db.updateLastPingReceived(fromID, time.Now())
   613  	return nil
   614  }
   615  
   616  func (req *ping) name() string { return "PING/v4" }
   617  
   618  func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   619  	if expired(req.Expiration) {
   620  		return errExpired
   621  	}
   622  	if !t.handleReply(fromID, pongPacket, req) {
   623  		return errUnsolicitedReply
   624  	}
   625  	t.db.updateLastPongReceived(fromID, time.Now())
   626  	return nil
   627  }
   628  
   629  func (req *pong) name() string { return "PONG/v4" }
   630  
   631  func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   632  	if expired(req.Expiration) {
   633  		return errExpired
   634  	}
   635  	if !t.db.hasBond(fromID) {
   636  //不存在端点验证pong,我们不处理数据包。这可以防止
   637  //攻击向量,发现协议可用于放大
   638  //DDoS攻击。恶意参与者将使用IP地址发送findnode请求
   639  //目标的UDP端口作为源地址。findnode的接收者
   640  //然后,包将发送一个邻居包(比
   641  //找到受害者。
   642  		return errUnknownNode
   643  	}
   644  	target := crypto.Keccak256Hash(req.Target[:])
   645  	t.mutex.Lock()
   646  	closest := t.closest(target, bucketSize).entries
   647  	t.mutex.Unlock()
   648  
   649  	p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())}
   650  	var sent bool
   651  //以块形式发送邻居,每个数据包最多有maxneighbors
   652  //低于1280字节的限制。
   653  	for _, n := range closest {
   654  		if netutil.CheckRelayIP(from.IP, n.IP) == nil {
   655  			p.Nodes = append(p.Nodes, nodeToRPC(n))
   656  		}
   657  		if len(p.Nodes) == maxNeighbors {
   658  			t.send(from, neighborsPacket, &p)
   659  			p.Nodes = p.Nodes[:0]
   660  			sent = true
   661  		}
   662  	}
   663  	if len(p.Nodes) > 0 || !sent {
   664  		t.send(from, neighborsPacket, &p)
   665  	}
   666  	return nil
   667  }
   668  
   669  func (req *findnode) name() string { return "FINDNODE/v4" }
   670  
   671  func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error {
   672  	if expired(req.Expiration) {
   673  		return errExpired
   674  	}
   675  	if !t.handleReply(fromID, neighborsPacket, req) {
   676  		return errUnsolicitedReply
   677  	}
   678  	return nil
   679  }
   680  
   681  func (req *neighbors) name() string { return "NEIGHBORS/v4" }
   682  
   683  func expired(ts uint64) bool {
   684  	return time.Unix(int64(ts), 0).Before(time.Now())
   685  }
   686