github.com/klaytn/klaytn@v1.12.1/networks/p2p/discover/udp.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from p2p/discover/udp.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package discover 22 23 import ( 24 "bytes" 25 "container/list" 26 "crypto/ecdsa" 27 "errors" 28 "fmt" 29 "net" 30 "time" 31 32 "github.com/klaytn/klaytn/crypto" 33 "github.com/klaytn/klaytn/networks/p2p/nat" 34 "github.com/klaytn/klaytn/networks/p2p/netutil" 35 "github.com/klaytn/klaytn/rlp" 36 ) 37 38 const Version = 4 39 40 // Errors 41 var ( 42 errPacketTooSmall = errors.New("too small") 43 errBadHash = errors.New("bad hash") 44 errExpired = errors.New("expired") 45 errUnsolicitedReply = errors.New("unsolicited reply") 46 errUnknownNode = errors.New("unknown node") 47 errTimeout = errors.New("RPC timeout") 48 errClockWarp = errors.New("reply deadline too far in the future") 49 errClosed = errors.New("socket closed") 50 errUnauthorized = errors.New("unauthorized node") 51 errMismatchNetwork = errors.New("mismatch network id") 52 ) 53 54 // Timeouts 55 const ( 56 respTimeout = 500 * time.Millisecond 57 expiration = 20 * time.Second 58 59 ntpFailureThreshold = 32 // Continuous timeouts after which to check NTP 60 ntpWarningCooldown = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning 61 driftThreshold = 1 * time.Second // Allowed clock drift before warning user 62 ) 63 64 // RPC packet types 65 const ( 66 pingPacket = iota + 1 // zero is 'reserved' 67 pongPacket 68 findnodePacket 69 neighborsPacket 70 ) 71 72 // Node types 73 const ( 74 NodeTypeUnknown = NodeType(iota) 75 NodeTypeCN 76 NodeTypePN 77 NodeTypeEN 78 NodeTypeBN 79 ) 80 81 // RPC request structures 82 type ( 83 ping struct { 84 NetworkID uint64 85 Version uint 86 From, To rpcEndpoint 87 Expiration uint64 88 // Ignore additional fields (for forward compatibility). 89 Rest []rlp.RawValue `rlp:"tail"` 90 } 91 92 // pong is the reply to ping. 93 pong struct { 94 // This field should mirror the UDP envelope address 95 // of the ping packet, which provides a way to discover the 96 // the external address (after NAT). 97 To rpcEndpoint 98 99 ReplyTok []byte // This contains the hash of the ping packet. 100 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 101 // Ignore additional fields (for forward compatibility). 102 Rest []rlp.RawValue `rlp:"tail"` 103 } 104 105 // findnode is a query for nodes close to the given target. 106 findnode struct { 107 Target NodeID // doesn't need to be an actual public key 108 TargetType NodeType 109 Expiration uint64 110 // Ignore additional fields (for forward compatibility). 111 Rest []rlp.RawValue `rlp:"tail"` 112 } 113 114 // reply to findnode 115 neighbors struct { 116 TargetType NodeType 117 Nodes []rpcNode 118 Expiration uint64 119 // Ignore additional fields (for forward compatibility). 120 Rest []rlp.RawValue `rlp:"tail"` 121 } 122 123 rpcNode struct { 124 IP net.IP // len 4 for IPv4 or 16 for IPv6 125 UDP uint16 // for discovery protocol 126 TCP uint16 // for RLPx protocol 127 ID NodeID 128 NType NodeType // NodeType (CN, PN, EN, BN) 129 } 130 131 rpcEndpoint struct { 132 IP net.IP // len 4 for IPv4 or 16 for IPv6 133 UDP uint16 // for discovery protocol 134 TCP uint16 // for RLPx protocol 135 NType NodeType // NodeType (CN, PN, EN, BN) 136 } 137 138 // TODO-Klaytn Change private type 139 NodeType uint8 140 ) 141 142 func makeEndpoint(addr *net.UDPAddr, tcpPort uint16, nType NodeType) rpcEndpoint { 143 ip := addr.IP.To4() 144 if ip == nil { 145 ip = addr.IP.To16() 146 } 147 return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort, NType: nType} 148 } 149 150 func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { 151 if rn.UDP <= 1024 { 152 return nil, errors.New("low port") 153 } 154 if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { 155 return nil, err 156 } 157 if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { 158 return nil, errors.New("not contained in netrestrict whitelist") 159 } 160 n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP, nil, rn.NType) 161 err := n.validateComplete() 162 return n, err 163 } 164 165 func nodeToRPC(n *Node) rpcNode { 166 return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP, NType: n.NType} 167 } 168 169 type packet interface { 170 handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error 171 name() string 172 } 173 174 type conn interface { 175 ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) 176 WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) 177 Close() error 178 LocalAddr() net.Addr 179 } 180 181 // udp implements the RPC protocol. 182 type udp struct { 183 networkID uint64 184 conn conn 185 netrestrict *netutil.Netlist 186 priv *ecdsa.PrivateKey 187 ourEndpoint rpcEndpoint 188 189 addpending chan *pending 190 gotreply chan reply 191 192 closing chan struct{} 193 nat nat.Interface 194 195 Discovery 196 } 197 198 // pending represents a pending reply. 199 // 200 // some implementations of the protocol wish to send more than one 201 // reply packet to findnode. in general, any neighbors packet cannot 202 // be matched up with a specific findnode packet. 203 // 204 // our implementation handles this by storing a callback function for 205 // each pending reply. incoming packets from a node are dispatched 206 // to all the callback functions for that node. 207 type pending struct { 208 // these fields must match in the reply. 209 from NodeID 210 ptype byte 211 targetType NodeType 212 213 // time when the request must complete 214 deadline time.Time 215 216 // callback is called when a matching reply arrives. if it returns 217 // true, the callback is removed from the pending reply queue. 218 // if it returns false, the reply is considered incomplete and 219 // the callback will be invoked again for the next matching reply. 220 callback func(resp interface{}) (done bool) 221 222 // errc receives nil when the callback indicates completion or an 223 // error if no further reply is received within the timeout. 224 errc chan<- error 225 } 226 227 func (p *pending) String() string { 228 var typeStr string 229 switch p.ptype { 230 case pingPacket: 231 typeStr = "PING" 232 case pongPacket: 233 typeStr = "PONG" 234 case findnodePacket: 235 typeStr = "FINDNODE" 236 case neighborsPacket: 237 typeStr = "NEIGHBORS" 238 default: 239 typeStr = "UNKNOWN" 240 } 241 return fmt.Sprintf("pending [from:%s, type:%s, targetType:%d, deadline:%s]", p.from, typeStr, p.targetType, p.deadline) 242 } 243 244 type reply struct { 245 from NodeID 246 ptype byte 247 data interface{} 248 // loop indicates whether there was 249 // a matching request by sending on this channel. 250 matched chan<- bool 251 } 252 253 // ReadPacket is sent to the unhandled channel when it could not be processed 254 type ReadPacket struct { 255 Data []byte 256 Addr *net.UDPAddr 257 } 258 259 // Config holds Table-related settings. 260 type Config struct { 261 NetworkID uint64 262 // These settings are required and configure the UDP listener: 263 PrivateKey *ecdsa.PrivateKey 264 265 // These settings are optional: 266 AnnounceAddr *net.UDPAddr // local address announced in the DHT 267 NodeDBPath string // if set, the node database is stored at this filesystem location 268 NetRestrict *netutil.Netlist // network whitelist 269 Bootnodes []*Node // list of bootstrap nodes 270 Unhandled chan<- ReadPacket // unhandled packets are sent on this channel 271 272 // These settings are required for create Table and UDP 273 Id NodeID 274 Addr *net.UDPAddr 275 udp transport 276 Conn conn 277 NodeType NodeType 278 279 // These settings are required for discovery packet control 280 MaxNeighborsNode uint 281 AuthorizedNodes []*Node 282 } 283 284 // ListenUDP returns a new table that listens for UDP packets on laddr. 285 func ListenUDP(cfg *Config) (Discovery, error) { 286 discv, _, err := newUDP(cfg) 287 if err != nil { 288 return nil, err 289 } 290 logger.Info("UDP listener up", "self", discv.Self()) 291 return discv, nil 292 } 293 294 func newUDP(cfg *Config) (Discovery, *udp, error) { 295 udp := &udp{ 296 networkID: cfg.NetworkID, 297 conn: cfg.Conn, 298 priv: cfg.PrivateKey, 299 netrestrict: cfg.NetRestrict, 300 closing: make(chan struct{}), 301 gotreply: make(chan reply), 302 addpending: make(chan *pending), 303 } 304 realaddr := cfg.Addr 305 if cfg.AnnounceAddr != nil { 306 realaddr = cfg.AnnounceAddr 307 } 308 // TODO: separate TCP port 309 udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port), cfg.NodeType) 310 cfg.udp = udp 311 312 var err error 313 udp.Discovery, err = NewDiscovery(cfg) 314 if err != nil { 315 return nil, nil, err 316 } 317 go udp.Discovery.(*Table).loop() // TODO-Klaytn-Node There is only one concrete type(Table) for Discovery. Refactor Discovery interface for their proper objective. 318 go udp.loop() 319 go udp.readLoop(cfg.Unhandled) 320 return udp.Discovery, udp, nil 321 } 322 323 func (t *udp) close() { 324 close(t.closing) 325 t.conn.Close() 326 // TODO: wait for the loops to end. 327 } 328 329 // ping sends a ping message to the given node and waits for a reply. 330 func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error { 331 req := &ping{ 332 NetworkID: t.networkID, 333 Version: Version, 334 From: t.ourEndpoint, 335 To: makeEndpoint(toaddr, 0, NodeTypeUnknown), // TODO: maybe use known TCP port from DB 336 Expiration: uint64(time.Now().Add(expiration).Unix()), 337 } 338 packet, hash, err := encodePacket(t.priv, pingPacket, req) 339 if err != nil { 340 return err 341 } 342 errc := t.pending(toid, pongPacket, NodeTypeUnknown, func(p interface{}) bool { 343 return bytes.Equal(p.(*pong).ReplyTok, hash) 344 }) 345 pingMeter.Mark(1) 346 t.write(toaddr, req.name(), packet) 347 err = <-errc 348 if err == nil { 349 pongMeter.Mark(1) 350 } 351 return err 352 } 353 354 func (t *udp) waitping(from NodeID) error { 355 return <-t.pending(from, pingPacket, NodeTypeUnknown, func(interface{}) bool { return true }) 356 } 357 358 // findnode sends a findnode request to the given node and waits until 359 // the node has sent up to k neighbors. 360 func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID, targetNT NodeType, max int) ([]*Node, error) { 361 logger.Trace("[udp] findnode", "toid", toid, "toaddr", toaddr, "target", target, 362 "targetNodeType", targetNT) 363 nodes := make([]*Node, 0, bucketSize) 364 nreceived := 0 365 errc := t.pending(toid, neighborsPacket, targetNT, func(r interface{}) bool { 366 reply := r.(*neighbors) 367 for _, rn := range reply.Nodes { 368 nreceived++ 369 n, err := t.nodeFromRPC(toaddr, rn) 370 if err != nil { 371 logger.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err) 372 continue 373 } 374 nodes = append(nodes, n) 375 } 376 return nreceived >= max 377 }) 378 _, err := t.send(toaddr, findnodePacket, &findnode{ 379 Target: target, 380 TargetType: targetNT, 381 Expiration: uint64(time.Now().Add(expiration).Unix()), 382 }) 383 if err != nil { 384 logger.Debug("[udp] findnode: failed to send FINDNODE", "err", err) 385 } 386 387 findNodesMeter.Mark(1) 388 err = <-errc 389 if err != nil { 390 neighborsMeter.Mark(1) 391 } 392 logger.Trace("[udp] findnode", "len(nodes)", len(nodes), "toid", toid, "toaddr", toaddr, "target", 393 target, "targetNodeType", targetNT) 394 return nodes, err 395 } 396 397 // pending adds a reply callback to the pending reply queue. 398 // see the documentation of type pending for a detailed explanation. 399 func (t *udp) pending(id NodeID, ptype byte, targetType NodeType, callback func(interface{}) bool) <-chan error { 400 ch := make(chan error, 1) 401 p := &pending{from: id, ptype: ptype, targetType: targetType, callback: callback, errc: ch} 402 select { 403 case t.addpending <- p: 404 // loop will handle it 405 case <-t.closing: 406 ch <- errClosed 407 } 408 return ch 409 } 410 411 func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool { 412 matched := make(chan bool, 1) 413 select { 414 case t.gotreply <- reply{from, ptype, req, matched}: 415 // loop will handle it 416 return <-matched 417 case <-t.closing: 418 return false 419 } 420 } 421 422 // loop runs in its own goroutine. it keeps track of 423 // the refresh timer and the pending reply queue. 424 func (t *udp) loop() { 425 var ( 426 plist = list.New() 427 timeout = time.NewTimer(0) 428 nextTimeout *pending // head of plist when timeout was last reset 429 contTimeouts = 0 // number of continuous timeouts to do NTP checks 430 ntpWarnTime = time.Unix(0, 0) 431 ) 432 <-timeout.C // ignore first timeout 433 defer timeout.Stop() 434 435 resetTimeout := func() { 436 if plist.Front() == nil || nextTimeout == plist.Front().Value { 437 return 438 } 439 // Start the timer so it fires when the next pending reply has expired. 440 now := time.Now() 441 for el := plist.Front(); el != nil; el = el.Next() { 442 nextTimeout = el.Value.(*pending) 443 if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { 444 timeout.Reset(dist) 445 return 446 } 447 // Remove pending replies whose deadline is too far in the 448 // future. These can occur if the system clock jumped 449 // backwards after the deadline was assigned. 450 nextTimeout.errc <- errClockWarp 451 plist.Remove(el) 452 } 453 nextTimeout = nil 454 timeout.Stop() 455 } 456 457 for { 458 resetTimeout() 459 460 select { 461 case <-t.closing: 462 for el := plist.Front(); el != nil; el = el.Next() { 463 el.Value.(*pending).errc <- errClosed 464 } 465 return 466 467 case p := <-t.addpending: 468 p.deadline = time.Now().Add(respTimeout) 469 plist.PushBack(p) 470 if p.ptype == pongPacket { 471 pendingPongCounter.Inc(1) 472 } else if p.ptype == neighborsPacket { 473 pendingNeighborsCounter.Inc(1) 474 } 475 476 case r := <-t.gotreply: 477 var matched bool 478 for el := plist.Front(); el != nil; el = el.Next() { 479 p := el.Value.(*pending) 480 if p.from == r.from && p.ptype == r.ptype { 481 if p.ptype == pongPacket { 482 pendingPongCounter.Dec(1) 483 } else if p.ptype == neighborsPacket { 484 if r.data.(*neighbors).TargetType != p.targetType { 485 continue 486 } 487 pendingNeighborsCounter.Dec(1) 488 } 489 matched = true 490 // Remove the matcher if its callback indicates 491 // that all replies have been received. This is 492 // required for packet types that expect multiple 493 // reply packets. 494 if p.callback(r.data) { 495 p.errc <- nil 496 plist.Remove(el) 497 } 498 // Reset the continuous timeout counter (time drift detection) 499 contTimeouts = 0 500 } 501 } 502 r.matched <- matched 503 504 case now := <-timeout.C: 505 nextTimeout = nil 506 507 // Notify and remove callbacks whose deadline is in the past. 508 for el := plist.Front(); el != nil; el = el.Next() { 509 p := el.Value.(*pending) 510 if now.After(p.deadline) || now.Equal(p.deadline) { 511 p.errc <- errTimeout 512 plist.Remove(el) 513 contTimeouts++ 514 } 515 } 516 // If we've accumulated too many timeouts, do an NTP time sync check 517 if contTimeouts > ntpFailureThreshold { 518 if time.Since(ntpWarnTime) >= ntpWarningCooldown { 519 ntpWarnTime = time.Now() 520 go checkClockDrift() 521 } 522 contTimeouts = 0 523 } 524 } 525 } 526 } 527 528 const ( 529 macSize = 256 / 8 530 sigSize = 520 / 8 531 headSize = macSize + sigSize // space of packet frame data 532 ) 533 534 var ( 535 headSpace = make([]byte, headSize) 536 537 // Neighbors replies are sent across multiple packets to 538 // stay below the 1280 byte limit. We compute the maximum number 539 // of entries by stuffing a packet until it grows too large. 540 maxNeighbors int 541 ) 542 543 func init() { 544 p := neighbors{Expiration: ^uint64(0)} 545 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 546 for n := 0; ; n++ { 547 p.Nodes = append(p.Nodes, maxSizeNode) 548 size, _, err := rlp.EncodeToReader(p) 549 if err != nil { 550 // If this ever happens, it will be caught by the unit tests. 551 panic("cannot encode: " + err.Error()) 552 } 553 if headSize+size+1 >= 1280 { 554 maxNeighbors = n 555 break 556 } 557 } 558 } 559 560 func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) ([]byte, error) { 561 packet, hash, err := encodePacket(t.priv, ptype, req) 562 if err != nil { 563 return hash, err 564 } 565 return hash, t.write(toaddr, req.name(), packet) 566 } 567 568 func (t *udp) write(toaddr *net.UDPAddr, what string, packet []byte) error { 569 _, err := t.conn.WriteToUDP(packet, toaddr) 570 logger.Trace(">> "+what, "addr", toaddr, "err", err) 571 return err 572 } 573 574 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) (packet, hash []byte, err error) { 575 b := new(bytes.Buffer) 576 b.Write(headSpace) 577 b.WriteByte(ptype) 578 if err := rlp.Encode(b, req); err != nil { 579 logger.Error("Can't encode discv4 packet", "err", err) 580 return nil, nil, err 581 } 582 packet = b.Bytes() 583 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 584 if err != nil { 585 logger.Error("Can't sign discv4 packet", "err", err) 586 return nil, nil, err 587 } 588 copy(packet[macSize:], sig) 589 // add the hash to the front. Note: this doesn't protect the 590 // packet in any way. Our public key will be part of this hash in 591 // The future. 592 hash = crypto.Keccak256(packet[macSize:]) 593 copy(packet, hash) 594 return packet, hash, nil 595 } 596 597 // readLoop runs in its own goroutine. it handles incoming UDP packets. 598 func (t *udp) readLoop(unhandled chan<- ReadPacket) { 599 defer t.conn.Close() 600 if unhandled != nil { 601 defer close(unhandled) 602 } 603 // Discovery packets are defined to be no larger than 1280 bytes. 604 // Packets larger than this size will be cut at the end and treated 605 // as invalid because their hash won't match. 606 buf := make([]byte, 1280) 607 for { 608 nbytes, from, err := t.conn.ReadFromUDP(buf) 609 if netutil.IsTemporaryError(err) { 610 // Ignore temporary read errors. 611 logger.Debug("Temporary UDP read error", "err", err) 612 continue 613 } else if err != nil { 614 // Shut down the loop for permanent errors. 615 logger.Warn("UDP read error", "err", err) 616 return 617 } 618 if t.handlePacket(from, buf[:nbytes]) != nil && unhandled != nil { 619 select { 620 case unhandled <- ReadPacket{buf[:nbytes], from}: 621 default: 622 } 623 } 624 } 625 } 626 627 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 628 packet, fromID, hash, err := decodePacket(buf) 629 if err != nil { 630 logger.Warn("Bad discv4 packet", "addr", from, "err", err) 631 return err 632 } 633 logger.Trace("<< "+packet.name(), "addr", from, "err", err) 634 logger.Trace("[udp] handlePacket", "name", packet.name(), "packet", packet) 635 err = packet.handle(t, from, fromID, hash) 636 // TODO-Klaytn Count Error UDP Packets 637 udpPacketCounter.Inc(1) 638 return err 639 } 640 641 func decodePacket(buf []byte) (packet, NodeID, []byte, error) { 642 if len(buf) < headSize+1 { 643 return nil, NodeID{}, nil, errPacketTooSmall 644 } 645 hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] 646 shouldhash := crypto.Keccak256(buf[macSize:]) 647 if !bytes.Equal(hash, shouldhash) { 648 return nil, NodeID{}, nil, errBadHash 649 } 650 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 651 if err != nil { 652 return nil, NodeID{}, hash, err 653 } 654 var req packet 655 switch ptype := sigdata[0]; ptype { 656 case pingPacket: 657 req = new(ping) 658 case pongPacket: 659 req = new(pong) 660 case findnodePacket: 661 req = new(findnode) 662 case neighborsPacket: 663 req = new(neighbors) 664 default: 665 return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype) 666 } 667 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 668 err = s.Decode(req) 669 return req, fromID, hash, err 670 } 671 672 func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 673 logger.Trace("udp: ping: received", "from", fromID, "req.NetworkId", req.NetworkID, 674 "myNetworkId", t.networkID) 675 676 logger.Trace("udp: ping: send pong", "to", fromID) 677 if !t.Discovery.IsAuthorized(fromID, req.From.NType) { 678 logger.Trace("unauthorized node.", "nodeid", fromID, "nodetype", req.From.NType) 679 return errUnauthorized 680 } else { 681 logger.Debug("authorized node.", "nodeid", fromID, "nodetype", req.From.NType) 682 } 683 684 if req.NetworkID != t.networkID { 685 logger.Debug("udp: ping: mismatch networkid", "local", t.networkID, "remote", req.NetworkID) 686 mismatchNetworkCounter.Mark(1) 687 return errMismatchNetwork 688 } 689 690 if expired(req.Expiration) { 691 logger.Trace("udp: ping: expired", "from", fromID) 692 return errExpired 693 } 694 695 t.send(from, pongPacket, &pong{ 696 To: makeEndpoint(from, req.From.TCP, req.From.NType), 697 ReplyTok: mac, 698 Expiration: uint64(time.Now().Add(expiration).Unix()), 699 }) 700 if !t.handleReply(fromID, pingPacket, req) { 701 // Note: we're ignoring the provided IP address right now 702 go t.Bond(true, fromID, from, req.From.TCP, req.From.NType) 703 } 704 return nil 705 } 706 707 func (req *ping) name() string { return "PING/v4" } 708 709 func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 710 if expired(req.Expiration) { 711 return errExpired 712 } 713 if !t.handleReply(fromID, pongPacket, req) { 714 return errUnsolicitedReply 715 } 716 return nil 717 } 718 719 func (req *pong) name() string { return "PONG/v4" } 720 721 func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 722 if expired(req.Expiration) { 723 return errExpired 724 } 725 if !t.HasBond(fromID) { 726 // No bond exists, we don't process the packet. This prevents 727 // an attack vector where the discovery protocol could be used 728 // to amplify traffic in a DDOS attack. A malicious actor 729 // would send a findnode request with the IP address and UDP 730 // port of the target as the source address. The recipient of 731 // the findnode packet would then send a neighbors packet 732 // (which is a much bigger packet than findnode) to the victim. 733 return errUnknownNode 734 } 735 target := crypto.Keccak256Hash(req.Target[:]) 736 closest := t.RetrieveNodes(target, req.TargetType, bucketSize) // TODO-Klaytn-Node if NodeType is CN or PN, bucketSize is not a prefer variable. 737 738 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix()), TargetType: req.TargetType} 739 var sent bool 740 // Send neighbors in chunks with at most maxNeighbors per packet 741 // to stay below the 1280 byte limit. 742 for _, n := range closest { 743 if netutil.CheckRelayIP(from.IP, n.IP) == nil { 744 p.Nodes = append(p.Nodes, nodeToRPC(n)) 745 } 746 if len(p.Nodes) == maxNeighbors { 747 t.send(from, neighborsPacket, &p) 748 p.Nodes = p.Nodes[:0] 749 sent = true 750 } 751 } 752 if len(p.Nodes) > 0 || !sent { 753 t.send(from, neighborsPacket, &p) 754 } 755 return nil 756 } 757 758 func (req *findnode) name() string { return "FINDNODE/v4" } 759 760 func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 761 if expired(req.Expiration) { 762 return errExpired 763 } 764 if !t.handleReply(fromID, neighborsPacket, req) { 765 return errUnsolicitedReply 766 } 767 return nil 768 } 769 770 func (req *neighbors) name() string { return "NEIGHBORS/v4" } 771 772 func expired(ts uint64) bool { 773 return time.Unix(int64(ts), 0).Before(time.Now()) 774 }