github.com/jimmyx0x/go-ethereum@v1.10.28/p2p/discover/v4_udp.go (about) 1 // Copyright 2019 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 "context" 23 "crypto/ecdsa" 24 crand "crypto/rand" 25 "errors" 26 "fmt" 27 "io" 28 "net" 29 "sync" 30 "time" 31 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/p2p/discover/v4wire" 35 "github.com/ethereum/go-ethereum/p2p/enode" 36 "github.com/ethereum/go-ethereum/p2p/netutil" 37 ) 38 39 // Errors 40 var ( 41 errExpired = errors.New("expired") 42 errUnsolicitedReply = errors.New("unsolicited reply") 43 errUnknownNode = errors.New("unknown node") 44 errTimeout = errors.New("RPC timeout") 45 errClockWarp = errors.New("reply deadline too far in the future") 46 errClosed = errors.New("socket closed") 47 errLowPort = errors.New("low port") 48 ) 49 50 const ( 51 respTimeout = 500 * time.Millisecond 52 expiration = 20 * time.Second 53 bondExpiration = 24 * time.Hour 54 55 maxFindnodeFailures = 5 // nodes exceeding this limit are dropped 56 ntpFailureThreshold = 32 // Continuous timeouts after which to check NTP 57 ntpWarningCooldown = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning 58 driftThreshold = 10 * time.Second // Allowed clock drift before warning user 59 60 // Discovery packets are defined to be no larger than 1280 bytes. 61 // Packets larger than this size will be cut at the end and treated 62 // as invalid because their hash won't match. 63 maxPacketSize = 1280 64 ) 65 66 // UDPv4 implements the v4 wire protocol. 67 type UDPv4 struct { 68 conn UDPConn 69 log log.Logger 70 netrestrict *netutil.Netlist 71 priv *ecdsa.PrivateKey 72 localNode *enode.LocalNode 73 db *enode.DB 74 tab *Table 75 closeOnce sync.Once 76 wg sync.WaitGroup 77 78 addReplyMatcher chan *replyMatcher 79 gotreply chan reply 80 closeCtx context.Context 81 cancelCloseCtx context.CancelFunc 82 } 83 84 // replyMatcher represents a pending reply. 85 // 86 // Some implementations of the protocol wish to send more than one 87 // reply packet to findnode. In general, any neighbors packet cannot 88 // be matched up with a specific findnode packet. 89 // 90 // Our implementation handles this by storing a callback function for 91 // each pending reply. Incoming packets from a node are dispatched 92 // to all callback functions for that node. 93 type replyMatcher struct { 94 // these fields must match in the reply. 95 from enode.ID 96 ip net.IP 97 ptype byte 98 99 // time when the request must complete 100 deadline time.Time 101 102 // callback is called when a matching reply arrives. If it returns matched == true, the 103 // reply was acceptable. The second return value indicates whether the callback should 104 // be removed from the pending reply queue. If it returns false, the reply is considered 105 // incomplete and the callback will be invoked again for the next matching reply. 106 callback replyMatchFunc 107 108 // errc receives nil when the callback indicates completion or an 109 // error if no further reply is received within the timeout. 110 errc chan error 111 112 // reply contains the most recent reply. This field is safe for reading after errc has 113 // received a value. 114 reply v4wire.Packet 115 } 116 117 type replyMatchFunc func(v4wire.Packet) (matched bool, requestDone bool) 118 119 // reply is a reply packet from a certain node. 120 type reply struct { 121 from enode.ID 122 ip net.IP 123 data v4wire.Packet 124 // loop indicates whether there was 125 // a matching request by sending on this channel. 126 matched chan<- bool 127 } 128 129 func ListenV4(c UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv4, error) { 130 cfg = cfg.withDefaults() 131 closeCtx, cancel := context.WithCancel(context.Background()) 132 t := &UDPv4{ 133 conn: c, 134 priv: cfg.PrivateKey, 135 netrestrict: cfg.NetRestrict, 136 localNode: ln, 137 db: ln.Database(), 138 gotreply: make(chan reply), 139 addReplyMatcher: make(chan *replyMatcher), 140 closeCtx: closeCtx, 141 cancelCloseCtx: cancel, 142 log: cfg.Log, 143 } 144 145 tab, err := newTable(t, ln.Database(), cfg.Bootnodes, t.log) 146 if err != nil { 147 return nil, err 148 } 149 t.tab = tab 150 go tab.loop() 151 152 t.wg.Add(2) 153 go t.loop() 154 go t.readLoop(cfg.Unhandled) 155 return t, nil 156 } 157 158 // Self returns the local node. 159 func (t *UDPv4) Self() *enode.Node { 160 return t.localNode.Node() 161 } 162 163 // Close shuts down the socket and aborts any running queries. 164 func (t *UDPv4) Close() { 165 t.closeOnce.Do(func() { 166 t.cancelCloseCtx() 167 t.conn.Close() 168 t.wg.Wait() 169 t.tab.close() 170 }) 171 } 172 173 // Resolve searches for a specific node with the given ID and tries to get the most recent 174 // version of the node record for it. It returns n if the node could not be resolved. 175 func (t *UDPv4) Resolve(n *enode.Node) *enode.Node { 176 // Try asking directly. This works if the node is still responding on the endpoint we have. 177 if rn, err := t.RequestENR(n); err == nil { 178 return rn 179 } 180 // Check table for the ID, we might have a newer version there. 181 if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { 182 n = intable 183 if rn, err := t.RequestENR(n); err == nil { 184 return rn 185 } 186 } 187 // Otherwise perform a network lookup. 188 var key enode.Secp256k1 189 if n.Load(&key) != nil { 190 return n // no secp256k1 key 191 } 192 result := t.LookupPubkey((*ecdsa.PublicKey)(&key)) 193 for _, rn := range result { 194 if rn.ID() == n.ID() { 195 if rn, err := t.RequestENR(rn); err == nil { 196 return rn 197 } 198 } 199 } 200 return n 201 } 202 203 func (t *UDPv4) ourEndpoint() v4wire.Endpoint { 204 n := t.Self() 205 a := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} 206 return v4wire.NewEndpoint(a, uint16(n.TCP())) 207 } 208 209 // Ping sends a ping message to the given node. 210 func (t *UDPv4) Ping(n *enode.Node) error { 211 _, err := t.ping(n) 212 return err 213 } 214 215 // ping sends a ping message to the given node and waits for a reply. 216 func (t *UDPv4) ping(n *enode.Node) (seq uint64, err error) { 217 rm := t.sendPing(n.ID(), &net.UDPAddr{IP: n.IP(), Port: n.UDP()}, nil) 218 if err = <-rm.errc; err == nil { 219 seq = rm.reply.(*v4wire.Pong).ENRSeq 220 } 221 return seq, err 222 } 223 224 // sendPing sends a ping message to the given node and invokes the callback 225 // when the reply arrives. 226 func (t *UDPv4) sendPing(toid enode.ID, toaddr *net.UDPAddr, callback func()) *replyMatcher { 227 req := t.makePing(toaddr) 228 packet, hash, err := v4wire.Encode(t.priv, req) 229 if err != nil { 230 errc := make(chan error, 1) 231 errc <- err 232 return &replyMatcher{errc: errc} 233 } 234 // Add a matcher for the reply to the pending reply queue. Pongs are matched if they 235 // reference the ping we're about to send. 236 rm := t.pending(toid, toaddr.IP, v4wire.PongPacket, func(p v4wire.Packet) (matched bool, requestDone bool) { 237 matched = bytes.Equal(p.(*v4wire.Pong).ReplyTok, hash) 238 if matched && callback != nil { 239 callback() 240 } 241 return matched, matched 242 }) 243 // Send the packet. 244 t.localNode.UDPContact(toaddr) 245 t.write(toaddr, toid, req.Name(), packet) 246 return rm 247 } 248 249 func (t *UDPv4) makePing(toaddr *net.UDPAddr) *v4wire.Ping { 250 return &v4wire.Ping{ 251 Version: 4, 252 From: t.ourEndpoint(), 253 To: v4wire.NewEndpoint(toaddr, 0), 254 Expiration: uint64(time.Now().Add(expiration).Unix()), 255 ENRSeq: t.localNode.Node().Seq(), 256 } 257 } 258 259 // LookupPubkey finds the closest nodes to the given public key. 260 func (t *UDPv4) LookupPubkey(key *ecdsa.PublicKey) []*enode.Node { 261 if t.tab.len() == 0 { 262 // All nodes were dropped, refresh. The very first query will hit this 263 // case and run the bootstrapping logic. 264 <-t.tab.refresh() 265 } 266 return t.newLookup(t.closeCtx, encodePubkey(key)).run() 267 } 268 269 // RandomNodes is an iterator yielding nodes from a random walk of the DHT. 270 func (t *UDPv4) RandomNodes() enode.Iterator { 271 return newLookupIterator(t.closeCtx, t.newRandomLookup) 272 } 273 274 // lookupRandom implements transport. 275 func (t *UDPv4) lookupRandom() []*enode.Node { 276 return t.newRandomLookup(t.closeCtx).run() 277 } 278 279 // lookupSelf implements transport. 280 func (t *UDPv4) lookupSelf() []*enode.Node { 281 return t.newLookup(t.closeCtx, encodePubkey(&t.priv.PublicKey)).run() 282 } 283 284 func (t *UDPv4) newRandomLookup(ctx context.Context) *lookup { 285 var target encPubkey 286 crand.Read(target[:]) 287 return t.newLookup(ctx, target) 288 } 289 290 func (t *UDPv4) newLookup(ctx context.Context, targetKey encPubkey) *lookup { 291 target := enode.ID(crypto.Keccak256Hash(targetKey[:])) 292 ekey := v4wire.Pubkey(targetKey) 293 it := newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { 294 return t.findnode(n.ID(), n.addr(), ekey) 295 }) 296 return it 297 } 298 299 // findnode sends a findnode request to the given node and waits until 300 // the node has sent up to k neighbors. 301 func (t *UDPv4) findnode(toid enode.ID, toaddr *net.UDPAddr, target v4wire.Pubkey) ([]*node, error) { 302 t.ensureBond(toid, toaddr) 303 304 // Add a matcher for 'neighbours' replies to the pending reply queue. The matcher is 305 // active until enough nodes have been received. 306 nodes := make([]*node, 0, bucketSize) 307 nreceived := 0 308 rm := t.pending(toid, toaddr.IP, v4wire.NeighborsPacket, func(r v4wire.Packet) (matched bool, requestDone bool) { 309 reply := r.(*v4wire.Neighbors) 310 for _, rn := range reply.Nodes { 311 nreceived++ 312 n, err := t.nodeFromRPC(toaddr, rn) 313 if err != nil { 314 t.log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err) 315 continue 316 } 317 nodes = append(nodes, n) 318 } 319 return true, nreceived >= bucketSize 320 }) 321 t.send(toaddr, toid, &v4wire.Findnode{ 322 Target: target, 323 Expiration: uint64(time.Now().Add(expiration).Unix()), 324 }) 325 // Ensure that callers don't see a timeout if the node actually responded. Since 326 // findnode can receive more than one neighbors response, the reply matcher will be 327 // active until the remote node sends enough nodes. If the remote end doesn't have 328 // enough nodes the reply matcher will time out waiting for the second reply, but 329 // there's no need for an error in that case. 330 err := <-rm.errc 331 if errors.Is(err, errTimeout) && rm.reply != nil { 332 err = nil 333 } 334 return nodes, err 335 } 336 337 // RequestENR sends ENRRequest to the given node and waits for a response. 338 func (t *UDPv4) RequestENR(n *enode.Node) (*enode.Node, error) { 339 addr := &net.UDPAddr{IP: n.IP(), Port: n.UDP()} 340 t.ensureBond(n.ID(), addr) 341 342 req := &v4wire.ENRRequest{ 343 Expiration: uint64(time.Now().Add(expiration).Unix()), 344 } 345 packet, hash, err := v4wire.Encode(t.priv, req) 346 if err != nil { 347 return nil, err 348 } 349 350 // Add a matcher for the reply to the pending reply queue. Responses are matched if 351 // they reference the request we're about to send. 352 rm := t.pending(n.ID(), addr.IP, v4wire.ENRResponsePacket, func(r v4wire.Packet) (matched bool, requestDone bool) { 353 matched = bytes.Equal(r.(*v4wire.ENRResponse).ReplyTok, hash) 354 return matched, matched 355 }) 356 // Send the packet and wait for the reply. 357 t.write(addr, n.ID(), req.Name(), packet) 358 if err := <-rm.errc; err != nil { 359 return nil, err 360 } 361 // Verify the response record. 362 respN, err := enode.New(enode.ValidSchemes, &rm.reply.(*v4wire.ENRResponse).Record) 363 if err != nil { 364 return nil, err 365 } 366 if respN.ID() != n.ID() { 367 return nil, fmt.Errorf("invalid ID in response record") 368 } 369 if respN.Seq() < n.Seq() { 370 return n, nil // response record is older 371 } 372 if err := netutil.CheckRelayIP(addr.IP, respN.IP()); err != nil { 373 return nil, fmt.Errorf("invalid IP in response record: %v", err) 374 } 375 return respN, nil 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 *UDPv4) pending(id enode.ID, ip net.IP, ptype byte, callback replyMatchFunc) *replyMatcher { 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.closeCtx.Done(): 387 ch <- errClosed 388 } 389 return p 390 } 391 392 // handleReply dispatches a reply packet, invoking reply matchers. It returns 393 // whether any matcher considered the packet acceptable. 394 func (t *UDPv4) handleReply(from enode.ID, fromIP net.IP, req v4wire.Packet) bool { 395 matched := make(chan bool, 1) 396 select { 397 case t.gotreply <- reply{from, fromIP, req, matched}: 398 // loop will handle it 399 return <-matched 400 case <-t.closeCtx.Done(): 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 *UDPv4) 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.closeCtx.Done(): 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.data.Kind() && p.ip.Equal(r.ip) { 461 ok, requestDone := p.callback(r.data) 462 matched = matched || ok 463 p.reply = r.data 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 r.matched <- matched 474 475 case now := <-timeout.C: 476 nextTimeout = nil 477 478 // Notify and remove callbacks whose deadline is in the past. 479 for el := plist.Front(); el != nil; el = el.Next() { 480 p := el.Value.(*replyMatcher) 481 if now.After(p.deadline) || now.Equal(p.deadline) { 482 p.errc <- errTimeout 483 plist.Remove(el) 484 contTimeouts++ 485 } 486 } 487 // If we've accumulated too many timeouts, do an NTP time sync check 488 if contTimeouts > ntpFailureThreshold { 489 if time.Since(ntpWarnTime) >= ntpWarningCooldown { 490 ntpWarnTime = time.Now() 491 go checkClockDrift() 492 } 493 contTimeouts = 0 494 } 495 } 496 } 497 } 498 499 func (t *UDPv4) send(toaddr *net.UDPAddr, toid enode.ID, req v4wire.Packet) ([]byte, error) { 500 packet, hash, err := v4wire.Encode(t.priv, req) 501 if err != nil { 502 return hash, err 503 } 504 return hash, t.write(toaddr, toid, req.Name(), packet) 505 } 506 507 func (t *UDPv4) write(toaddr *net.UDPAddr, toid enode.ID, what string, packet []byte) error { 508 _, err := t.conn.WriteToUDP(packet, toaddr) 509 t.log.Trace(">> "+what, "id", toid, "addr", toaddr, "err", err) 510 return err 511 } 512 513 // readLoop runs in its own goroutine. it handles incoming UDP packets. 514 func (t *UDPv4) readLoop(unhandled chan<- ReadPacket) { 515 defer t.wg.Done() 516 if unhandled != nil { 517 defer close(unhandled) 518 } 519 520 buf := make([]byte, maxPacketSize) 521 for { 522 nbytes, from, err := t.conn.ReadFromUDP(buf) 523 if netutil.IsTemporaryError(err) { 524 // Ignore temporary read errors. 525 t.log.Debug("Temporary UDP read error", "err", err) 526 continue 527 } else if err != nil { 528 // Shut down the loop for permanent errors. 529 if !errors.Is(err, io.EOF) { 530 t.log.Debug("UDP read error", "err", err) 531 } 532 return 533 } 534 if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil { 535 select { 536 case unhandled <- ReadPacket{buf[:nbytes], from}: 537 default: 538 } 539 } 540 } 541 } 542 543 func (t *UDPv4) handlePacket(from *net.UDPAddr, buf []byte) error { 544 rawpacket, fromKey, hash, err := v4wire.Decode(buf) 545 if err != nil { 546 t.log.Debug("Bad discv4 packet", "addr", from, "err", err) 547 return err 548 } 549 packet := t.wrapPacket(rawpacket) 550 fromID := fromKey.ID() 551 if err == nil && packet.preverify != nil { 552 err = packet.preverify(packet, from, fromID, fromKey) 553 } 554 t.log.Trace("<< "+packet.Name(), "id", fromID, "addr", from, "err", err) 555 if err == nil && packet.handle != nil { 556 packet.handle(packet, from, fromID, hash) 557 } 558 return err 559 } 560 561 // checkBond checks if the given node has a recent enough endpoint proof. 562 func (t *UDPv4) checkBond(id enode.ID, ip net.IP) bool { 563 return time.Since(t.db.LastPongReceived(id, ip)) < bondExpiration 564 } 565 566 // ensureBond solicits a ping from a node if we haven't seen a ping from it for a while. 567 // This ensures there is a valid endpoint proof on the remote end. 568 func (t *UDPv4) ensureBond(toid enode.ID, toaddr *net.UDPAddr) { 569 tooOld := time.Since(t.db.LastPingReceived(toid, toaddr.IP)) > bondExpiration 570 if tooOld || t.db.FindFails(toid, toaddr.IP) > maxFindnodeFailures { 571 rm := t.sendPing(toid, toaddr, nil) 572 <-rm.errc 573 // Wait for them to ping back and process our pong. 574 time.Sleep(respTimeout) 575 } 576 } 577 578 func (t *UDPv4) nodeFromRPC(sender *net.UDPAddr, rn v4wire.Node) (*node, error) { 579 if rn.UDP <= 1024 { 580 return nil, errLowPort 581 } 582 if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { 583 return nil, err 584 } 585 if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { 586 return nil, errors.New("not contained in netrestrict list") 587 } 588 key, err := v4wire.DecodePubkey(crypto.S256(), rn.ID) 589 if err != nil { 590 return nil, err 591 } 592 n := wrapNode(enode.NewV4(key, rn.IP, int(rn.TCP), int(rn.UDP))) 593 err = n.ValidateComplete() 594 return n, err 595 } 596 597 func nodeToRPC(n *node) v4wire.Node { 598 var key ecdsa.PublicKey 599 var ekey v4wire.Pubkey 600 if err := n.Load((*enode.Secp256k1)(&key)); err == nil { 601 ekey = v4wire.EncodePubkey(&key) 602 } 603 return v4wire.Node{ID: ekey, IP: n.IP(), UDP: uint16(n.UDP()), TCP: uint16(n.TCP())} 604 } 605 606 // wrapPacket returns the handler functions applicable to a packet. 607 func (t *UDPv4) wrapPacket(p v4wire.Packet) *packetHandlerV4 { 608 var h packetHandlerV4 609 h.Packet = p 610 switch p.(type) { 611 case *v4wire.Ping: 612 h.preverify = t.verifyPing 613 h.handle = t.handlePing 614 case *v4wire.Pong: 615 h.preverify = t.verifyPong 616 case *v4wire.Findnode: 617 h.preverify = t.verifyFindnode 618 h.handle = t.handleFindnode 619 case *v4wire.Neighbors: 620 h.preverify = t.verifyNeighbors 621 case *v4wire.ENRRequest: 622 h.preverify = t.verifyENRRequest 623 h.handle = t.handleENRRequest 624 case *v4wire.ENRResponse: 625 h.preverify = t.verifyENRResponse 626 } 627 return &h 628 } 629 630 // packetHandlerV4 wraps a packet with handler functions. 631 type packetHandlerV4 struct { 632 v4wire.Packet 633 senderKey *ecdsa.PublicKey // used for ping 634 635 // preverify checks whether the packet is valid and should be handled at all. 636 preverify func(p *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error 637 // handle handles the packet. 638 handle func(req *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) 639 } 640 641 // PING/v4 642 643 func (t *UDPv4) verifyPing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 644 req := h.Packet.(*v4wire.Ping) 645 646 senderKey, err := v4wire.DecodePubkey(crypto.S256(), fromKey) 647 if err != nil { 648 return err 649 } 650 if v4wire.Expired(req.Expiration) { 651 return errExpired 652 } 653 h.senderKey = senderKey 654 return nil 655 } 656 657 func (t *UDPv4) handlePing(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { 658 req := h.Packet.(*v4wire.Ping) 659 660 // Reply. 661 t.send(from, fromID, &v4wire.Pong{ 662 To: v4wire.NewEndpoint(from, req.From.TCP), 663 ReplyTok: mac, 664 Expiration: uint64(time.Now().Add(expiration).Unix()), 665 ENRSeq: t.localNode.Node().Seq(), 666 }) 667 668 // Ping back if our last pong on file is too far in the past. 669 n := wrapNode(enode.NewV4(h.senderKey, from.IP, int(req.From.TCP), from.Port)) 670 if time.Since(t.db.LastPongReceived(n.ID(), from.IP)) > bondExpiration { 671 t.sendPing(fromID, from, func() { 672 t.tab.addVerifiedNode(n) 673 }) 674 } else { 675 t.tab.addVerifiedNode(n) 676 } 677 678 // Update node database and endpoint predictor. 679 t.db.UpdateLastPingReceived(n.ID(), from.IP, time.Now()) 680 t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) 681 } 682 683 // PONG/v4 684 685 func (t *UDPv4) verifyPong(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 686 req := h.Packet.(*v4wire.Pong) 687 688 if v4wire.Expired(req.Expiration) { 689 return errExpired 690 } 691 if !t.handleReply(fromID, from.IP, req) { 692 return errUnsolicitedReply 693 } 694 t.localNode.UDPEndpointStatement(from, &net.UDPAddr{IP: req.To.IP, Port: int(req.To.UDP)}) 695 t.db.UpdateLastPongReceived(fromID, from.IP, time.Now()) 696 return nil 697 } 698 699 // FINDNODE/v4 700 701 func (t *UDPv4) verifyFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 702 req := h.Packet.(*v4wire.Findnode) 703 704 if v4wire.Expired(req.Expiration) { 705 return errExpired 706 } 707 if !t.checkBond(fromID, from.IP) { 708 // No endpoint proof pong exists, we don't process the packet. This prevents an 709 // attack vector where the discovery protocol could be used to amplify traffic in a 710 // DDOS attack. A malicious actor would send a findnode request with the IP address 711 // and UDP port of the target as the source address. The recipient of the findnode 712 // packet would then send a neighbors packet (which is a much bigger packet than 713 // findnode) to the victim. 714 return errUnknownNode 715 } 716 return nil 717 } 718 719 func (t *UDPv4) handleFindnode(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { 720 req := h.Packet.(*v4wire.Findnode) 721 722 // Determine closest nodes. 723 target := enode.ID(crypto.Keccak256Hash(req.Target[:])) 724 closest := t.tab.findnodeByID(target, bucketSize, true).entries 725 726 // Send neighbors in chunks with at most maxNeighbors per packet 727 // to stay below the packet size limit. 728 p := v4wire.Neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 729 var sent bool 730 for _, n := range closest { 731 if netutil.CheckRelayIP(from.IP, n.IP()) == nil { 732 p.Nodes = append(p.Nodes, nodeToRPC(n)) 733 } 734 if len(p.Nodes) == v4wire.MaxNeighbors { 735 t.send(from, fromID, &p) 736 p.Nodes = p.Nodes[:0] 737 sent = true 738 } 739 } 740 if len(p.Nodes) > 0 || !sent { 741 t.send(from, fromID, &p) 742 } 743 } 744 745 // NEIGHBORS/v4 746 747 func (t *UDPv4) verifyNeighbors(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 748 req := h.Packet.(*v4wire.Neighbors) 749 750 if v4wire.Expired(req.Expiration) { 751 return errExpired 752 } 753 if !t.handleReply(fromID, from.IP, h.Packet) { 754 return errUnsolicitedReply 755 } 756 return nil 757 } 758 759 // ENRREQUEST/v4 760 761 func (t *UDPv4) verifyENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 762 req := h.Packet.(*v4wire.ENRRequest) 763 764 if v4wire.Expired(req.Expiration) { 765 return errExpired 766 } 767 if !t.checkBond(fromID, from.IP) { 768 return errUnknownNode 769 } 770 return nil 771 } 772 773 func (t *UDPv4) handleENRRequest(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, mac []byte) { 774 t.send(from, fromID, &v4wire.ENRResponse{ 775 ReplyTok: mac, 776 Record: *t.localNode.Node().Record(), 777 }) 778 } 779 780 // ENRRESPONSE/v4 781 782 func (t *UDPv4) verifyENRResponse(h *packetHandlerV4, from *net.UDPAddr, fromID enode.ID, fromKey v4wire.Pubkey) error { 783 if !t.handleReply(fromID, from.IP, h.Packet) { 784 return errUnsolicitedReply 785 } 786 return nil 787 }