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