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