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