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