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