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