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