github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/p2p/discover/udp.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "bytes" 21 "container/list" 22 "crypto/ecdsa" 23 "errors" 24 "fmt" 25 "net" 26 "time" 27 28 "github.com/SmartMeshFoundation/Spectrum/crypto" 29 "github.com/SmartMeshFoundation/Spectrum/log" 30 "github.com/SmartMeshFoundation/Spectrum/p2p/nat" 31 "github.com/SmartMeshFoundation/Spectrum/p2p/netutil" 32 "github.com/SmartMeshFoundation/Spectrum/rlp" 33 ) 34 35 const Version = 4 36 37 // Errors 38 var ( 39 errPacketTooSmall = errors.New("too small") 40 errBadHash = errors.New("bad hash") 41 errExpired = errors.New("expired") 42 errUnsolicitedReply = errors.New("unsolicited reply") 43 errUnknownNode = errors.New("unknown node") 44 errTimeout = errors.New("RPC timeout") 45 errClockWarp = errors.New("reply deadline too far in the future") 46 errClosed = errors.New("socket closed") 47 ) 48 49 // Timeouts 50 const ( 51 respTimeout = 500 * time.Millisecond 52 sendTimeout = 500 * time.Millisecond 53 expiration = 20 * time.Second 54 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 60 // RPC packet types 61 const ( 62 //pingPacket = iota + 1 // zero is 'reserved' 63 pingPacket = iota + 10 // modify RPC packet types , reject other eth node connect 64 pongPacket 65 findnodePacket 66 neighborsPacket 67 ) 68 69 // RPC request structures 70 type ( 71 ping struct { 72 Version uint 73 From, To rpcEndpoint 74 Expiration uint64 75 // Ignore additional fields (for forward compatibility). 76 Rest []rlp.RawValue `rlp:"tail"` 77 } 78 79 // pong is the reply to ping. 80 pong struct { 81 // This field should mirror the UDP envelope address 82 // of the ping packet, which provides a way to discover the 83 // the external address (after NAT). 84 To rpcEndpoint 85 86 ReplyTok []byte // This contains the hash of the ping packet. 87 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 88 // Ignore additional fields (for forward compatibility). 89 Rest []rlp.RawValue `rlp:"tail"` 90 } 91 92 // findnode is a query for nodes close to the given target. 93 findnode struct { 94 Target NodeID // doesn't need to be an actual public key 95 Expiration uint64 96 // Ignore additional fields (for forward compatibility). 97 Rest []rlp.RawValue `rlp:"tail"` 98 } 99 100 // reply to findnode 101 neighbors struct { 102 Nodes []rpcNode 103 Expiration uint64 104 // Ignore additional fields (for forward compatibility). 105 Rest []rlp.RawValue `rlp:"tail"` 106 } 107 108 rpcNode struct { 109 IP net.IP // len 4 for IPv4 or 16 for IPv6 110 UDP uint16 // for discovery protocol 111 TCP uint16 // for RLPx protocol 112 ID NodeID 113 } 114 115 rpcEndpoint struct { 116 IP net.IP // len 4 for IPv4 or 16 for IPv6 117 UDP uint16 // for discovery protocol 118 TCP uint16 // for RLPx protocol 119 } 120 ) 121 122 func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { 123 ip := addr.IP.To4() 124 if ip == nil { 125 ip = addr.IP.To16() 126 } 127 return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 128 } 129 130 func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { 131 if rn.UDP <= 1024 { 132 return nil, errors.New("low port") 133 } 134 if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil { 135 return nil, err 136 } 137 if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { 138 return nil, errors.New("not contained in netrestrict whitelist") 139 } 140 n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP) 141 err := n.validateComplete() 142 return n, err 143 } 144 145 func nodeToRPC(n *Node) rpcNode { 146 return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP} 147 } 148 149 type packet interface { 150 handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error 151 name() string 152 } 153 154 type conn interface { 155 ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) 156 WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) 157 Close() error 158 LocalAddr() net.Addr 159 } 160 161 // udp implements the RPC protocol. 162 type udp struct { 163 conn conn 164 netrestrict *netutil.Netlist 165 priv *ecdsa.PrivateKey 166 ourEndpoint rpcEndpoint 167 168 addpending chan *pending 169 gotreply chan reply 170 171 closing chan struct{} 172 nat nat.Interface 173 174 *Table 175 } 176 177 // pending represents a pending reply. 178 // 179 // some implementations of the protocol wish to send more than one 180 // reply packet to findnode. in general, any neighbors packet cannot 181 // be matched up with a specific findnode packet. 182 // 183 // our implementation handles this by storing a callback function for 184 // each pending reply. incoming packets from a node are dispatched 185 // to all the callback functions for that node. 186 type pending struct { 187 // these fields must match in the reply. 188 from NodeID 189 ptype byte 190 191 // time when the request must complete 192 deadline time.Time 193 194 // callback is called when a matching reply arrives. if it returns 195 // true, the callback is removed from the pending reply queue. 196 // if it returns false, the reply is considered incomplete and 197 // the callback will be invoked again for the next matching reply. 198 callback func(resp interface{}) (done bool) 199 200 // errc receives nil when the callback indicates completion or an 201 // error if no further reply is received within the timeout. 202 errc chan<- error 203 } 204 205 type reply struct { 206 from NodeID 207 ptype byte 208 data interface{} 209 // loop indicates whether there was 210 // a matching request by sending on this channel. 211 matched chan<- bool 212 } 213 214 // ListenUDP returns a new table that listens for UDP packets on laddr. 215 func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, error) { 216 addr, err := net.ResolveUDPAddr("udp", laddr) 217 if err != nil { 218 return nil, err 219 } 220 conn, err := net.ListenUDP("udp", addr) 221 if err != nil { 222 return nil, err 223 } 224 tab, _, err := newUDP(priv, conn, natm, nodeDBPath, netrestrict) 225 if err != nil { 226 return nil, err 227 } 228 log.Info("UDP listener up", "self", tab.self) 229 return tab, nil 230 } 231 232 func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath string, netrestrict *netutil.Netlist) (*Table, *udp, error) { 233 udp := &udp{ 234 conn: c, 235 priv: priv, 236 netrestrict: netrestrict, 237 closing: make(chan struct{}), 238 gotreply: make(chan reply), 239 addpending: make(chan *pending), 240 } 241 realaddr := c.LocalAddr().(*net.UDPAddr) 242 if natm != nil { 243 if !realaddr.IP.IsLoopback() { 244 go nat.Map(natm, udp.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") 245 } 246 // TODO: react to external IP changes over time. 247 if ext, err := natm.ExternalIP(); err == nil { 248 realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} 249 } 250 } 251 // TODO: separate TCP port 252 udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port)) 253 tab, err := newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath) 254 if err != nil { 255 return nil, nil, err 256 } 257 udp.Table = tab 258 259 go udp.loop() 260 go udp.readLoop() 261 return udp.Table, udp, nil 262 } 263 264 func (t *udp) close() { 265 close(t.closing) 266 t.conn.Close() 267 // TODO: wait for the loops to end. 268 } 269 270 // ping sends a ping message to the given node and waits for a reply. 271 func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error { 272 // TODO: maybe check for ReplyTo field in callback to measure RTT 273 errc := t.pending(toid, pongPacket, func(interface{}) bool { return true }) 274 t.send(toaddr, pingPacket, &ping{ 275 Version: Version, 276 From: t.ourEndpoint, 277 To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB 278 Expiration: uint64(time.Now().Add(expiration).Unix()), 279 }) 280 return <-errc 281 } 282 283 func (t *udp) waitping(from NodeID) error { 284 return <-t.pending(from, pingPacket, func(interface{}) bool { return true }) 285 } 286 287 // findnode sends a findnode request to the given node and waits until 288 // the node has sent up to k neighbors. 289 func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { 290 nodes := make([]*Node, 0, bucketSize) 291 nreceived := 0 292 errc := t.pending(toid, neighborsPacket, func(r interface{}) bool { 293 reply := r.(*neighbors) 294 for _, rn := range reply.Nodes { 295 nreceived++ 296 n, err := t.nodeFromRPC(toaddr, rn) 297 if err != nil { 298 log.Trace("Invalid neighbor node received", "ip", rn.IP, "addr", toaddr, "err", err) 299 continue 300 } 301 nodes = append(nodes, n) 302 } 303 return nreceived >= bucketSize 304 }) 305 t.send(toaddr, findnodePacket, &findnode{ 306 Target: target, 307 Expiration: uint64(time.Now().Add(expiration).Unix()), 308 }) 309 err := <-errc 310 return nodes, err 311 } 312 313 // pending adds a reply callback to the pending reply queue. 314 // see the documentation of type pending for a detailed explanation. 315 func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-chan error { 316 ch := make(chan error, 1) 317 p := &pending{from: id, ptype: ptype, callback: callback, errc: ch} 318 select { 319 case t.addpending <- p: 320 // loop will handle it 321 case <-t.closing: 322 ch <- errClosed 323 } 324 return ch 325 } 326 327 func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool { 328 matched := make(chan bool, 1) 329 select { 330 case t.gotreply <- reply{from, ptype, req, matched}: 331 // loop will handle it 332 return <-matched 333 case <-t.closing: 334 return false 335 } 336 } 337 338 // loop runs in its own goroutine. it keeps track of 339 // the refresh timer and the pending reply queue. 340 func (t *udp) loop() { 341 var ( 342 plist = list.New() 343 timeout = time.NewTimer(0) 344 nextTimeout *pending // head of plist when timeout was last reset 345 contTimeouts = 0 // number of continuous timeouts to do NTP checks 346 ntpWarnTime = time.Unix(0, 0) 347 ) 348 <-timeout.C // ignore first timeout 349 defer timeout.Stop() 350 351 resetTimeout := func() { 352 if plist.Front() == nil || nextTimeout == plist.Front().Value { 353 return 354 } 355 // Start the timer so it fires when the next pending reply has expired. 356 now := time.Now() 357 for el := plist.Front(); el != nil; el = el.Next() { 358 nextTimeout = el.Value.(*pending) 359 if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { 360 timeout.Reset(dist) 361 return 362 } 363 // Remove pending replies whose deadline is too far in the 364 // future. These can occur if the system clock jumped 365 // backwards after the deadline was assigned. 366 nextTimeout.errc <- errClockWarp 367 plist.Remove(el) 368 } 369 nextTimeout = nil 370 timeout.Stop() 371 } 372 373 for { 374 resetTimeout() 375 376 select { 377 case <-t.closing: 378 for el := plist.Front(); el != nil; el = el.Next() { 379 el.Value.(*pending).errc <- errClosed 380 } 381 return 382 383 case p := <-t.addpending: 384 p.deadline = time.Now().Add(respTimeout) 385 plist.PushBack(p) 386 387 case r := <-t.gotreply: 388 var matched bool 389 for el := plist.Front(); el != nil; el = el.Next() { 390 p := el.Value.(*pending) 391 if p.from == r.from && p.ptype == r.ptype { 392 matched = true 393 // Remove the matcher if its callback indicates 394 // that all replies have been received. This is 395 // required for packet types that expect multiple 396 // reply packets. 397 if p.callback(r.data) { 398 p.errc <- nil 399 plist.Remove(el) 400 } 401 // Reset the continuous timeout counter (time drift detection) 402 contTimeouts = 0 403 } 404 } 405 r.matched <- matched 406 407 case now := <-timeout.C: 408 nextTimeout = nil 409 410 // Notify and remove callbacks whose deadline is in the past. 411 for el := plist.Front(); el != nil; el = el.Next() { 412 p := el.Value.(*pending) 413 if now.After(p.deadline) || now.Equal(p.deadline) { 414 p.errc <- errTimeout 415 plist.Remove(el) 416 contTimeouts++ 417 } 418 } 419 // If we've accumulated too many timeouts, do an NTP time sync check 420 if contTimeouts > ntpFailureThreshold { 421 if time.Since(ntpWarnTime) >= ntpWarningCooldown { 422 ntpWarnTime = time.Now() 423 go checkClockDrift() 424 } 425 contTimeouts = 0 426 } 427 } 428 } 429 } 430 431 const ( 432 macSize = 256 / 8 433 sigSize = 520 / 8 434 headSize = macSize + sigSize // space of packet frame data 435 ) 436 437 var ( 438 headSpace = make([]byte, headSize) 439 440 // Neighbors replies are sent across multiple packets to 441 // stay below the 1280 byte limit. We compute the maximum number 442 // of entries by stuffing a packet until it grows too large. 443 maxNeighbors int 444 ) 445 446 func init() { 447 p := neighbors{Expiration: ^uint64(0)} 448 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 449 for n := 0; ; n++ { 450 p.Nodes = append(p.Nodes, maxSizeNode) 451 size, _, err := rlp.EncodeToReader(p) 452 if err != nil { 453 // If this ever happens, it will be caught by the unit tests. 454 panic("cannot encode: " + err.Error()) 455 } 456 if headSize+size+1 >= 1280 { 457 maxNeighbors = n 458 break 459 } 460 } 461 } 462 463 func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req packet) error { 464 packet, err := encodePacket(t.priv, ptype, req) 465 if err != nil { 466 return err 467 } 468 _, err = t.conn.WriteToUDP(packet, toaddr) 469 log.Trace(">> "+req.name(), "addr", toaddr, "err", err) 470 return err 471 } 472 473 /* 474 unit byte 475 476 477 //Keccak256 return [32]byte hash 478 sig = Sign(Keccak256(|<-type(1)->|<-body->|),priv) // len 65 479 hash = Keccak256(|<-sig->|<-type(1)->|<-body->|) 480 packet = copy(packet, hash) 481 482 |<- head(97) ->|<-type(1)->|<-body->| 483 |<-hash(32)->|<-sig(65)->|<-type(1)->|<-body->| 484 485 */ 486 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, error) { 487 b := new(bytes.Buffer) 488 b.Write(headSpace) 489 b.WriteByte(ptype) 490 if err := rlp.Encode(b, req); err != nil { 491 log.Error("Can't encode discv4 packet", "err", err) 492 return nil, err 493 } 494 packet := b.Bytes() 495 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 496 if err != nil { 497 log.Error("Can't sign discv4 packet", "err", err) 498 return nil, err 499 } 500 copy(packet[macSize:], sig) 501 // add the hash to the front. Note: this doesn't protect the 502 // packet in any way. Our public key will be part of this hash in 503 // The future. 504 copy(packet, crypto.Keccak256(packet[macSize:])) 505 return packet, nil 506 } 507 508 // readLoop runs in its own goroutine. it handles incoming UDP packets. 509 func (t *udp) readLoop() { 510 defer t.conn.Close() 511 // Discovery packets are defined to be no larger than 1280 bytes. 512 // Packets larger than this size will be cut at the end and treated 513 // as invalid because their hash won't match. 514 buf := make([]byte, 1280) 515 for { 516 nbytes, from, err := t.conn.ReadFromUDP(buf) 517 if netutil.IsTemporaryError(err) { 518 // Ignore temporary read errors. 519 log.Debug("Temporary UDP read error", "err", err) 520 continue 521 } else if err != nil { 522 // Shut down the loop for permament errors. 523 log.Debug("UDP read error", "err", err) 524 return 525 } 526 t.handlePacket(from, buf[:nbytes]) 527 } 528 } 529 530 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 531 packet, fromID, hash, err := decodePacket(buf) 532 if err != nil { 533 log.Debug("Bad discv4 packet", "addr", from, "err", err) 534 return err 535 } 536 err = packet.handle(t, from, fromID, hash) 537 log.Trace("<< "+packet.name(), "addr", from, "err", err) 538 return err 539 } 540 541 func decodePacket(buf []byte) (packet, NodeID, []byte, error) { 542 if len(buf) < headSize+1 { 543 return nil, NodeID{}, nil, errPacketTooSmall 544 } 545 hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] 546 shouldhash := crypto.Keccak256(buf[macSize:]) 547 if !bytes.Equal(hash, shouldhash) { 548 return nil, NodeID{}, nil, errBadHash 549 } 550 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 551 if err != nil { 552 return nil, NodeID{}, hash, err 553 } 554 var req packet 555 switch ptype := sigdata[0]; ptype { 556 case pingPacket: 557 req = new(ping) 558 case pongPacket: 559 req = new(pong) 560 case findnodePacket: 561 req = new(findnode) 562 case neighborsPacket: 563 req = new(neighbors) 564 default: 565 return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype) 566 } 567 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 568 err = s.Decode(req) 569 return req, fromID, hash, err 570 } 571 572 func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 573 if expired(req.Expiration) { 574 return errExpired 575 } 576 t.send(from, pongPacket, &pong{ 577 To: makeEndpoint(from, req.From.TCP), 578 ReplyTok: mac, 579 Expiration: uint64(time.Now().Add(expiration).Unix()), 580 }) 581 if !t.handleReply(fromID, pingPacket, req) { 582 // Note: we're ignoring the provided IP address right now 583 go t.bond(true, fromID, from, req.From.TCP) 584 } 585 return nil 586 } 587 588 func (req *ping) name() string { return "PING/v4" } 589 590 func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 591 if expired(req.Expiration) { 592 return errExpired 593 } 594 if !t.handleReply(fromID, pongPacket, req) { 595 return errUnsolicitedReply 596 } 597 return nil 598 } 599 600 func (req *pong) name() string { return "PONG/v4" } 601 602 func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 603 if expired(req.Expiration) { 604 return errExpired 605 } 606 if t.db.node(fromID) == nil { 607 // No bond exists, we don't process the packet. This prevents 608 // an attack vector where the discovery protocol could be used 609 // to amplify traffic in a DDOS attack. A malicious actor 610 // would send a findnode request with the IP address and UDP 611 // port of the target as the source address. The recipient of 612 // the findnode packet would then send a neighbors packet 613 // (which is a much bigger packet than findnode) to the victim. 614 return errUnknownNode 615 } 616 target := crypto.Keccak256Hash(req.Target[:]) 617 t.mutex.Lock() 618 closest := t.closest(target, bucketSize).entries 619 t.mutex.Unlock() 620 621 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 622 // Send neighbors in chunks with at most maxNeighbors per packet 623 // to stay below the 1280 byte limit. 624 for i, n := range closest { 625 if netutil.CheckRelayIP(from.IP, n.IP) != nil { 626 continue 627 } 628 p.Nodes = append(p.Nodes, nodeToRPC(n)) 629 if len(p.Nodes) == maxNeighbors || i == len(closest)-1 { 630 t.send(from, neighborsPacket, &p) 631 p.Nodes = p.Nodes[:0] 632 } 633 } 634 return nil 635 } 636 637 func (req *findnode) name() string { return "FINDNODE/v4" } 638 639 func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 640 if expired(req.Expiration) { 641 return errExpired 642 } 643 if !t.handleReply(fromID, neighborsPacket, req) { 644 return errUnsolicitedReply 645 } 646 return nil 647 } 648 649 func (req *neighbors) name() string { return "NEIGHBORS/v4" } 650 651 func expired(ts uint64) bool { 652 return time.Unix(int64(ts), 0).Before(time.Now()) 653 }