github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/p2p/discover/v5_udp.go (about) 1 // Copyright 2020 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 "context" 22 "crypto/ecdsa" 23 crand "crypto/rand" 24 "errors" 25 "fmt" 26 "io" 27 "net" 28 "sync" 29 "time" 30 31 "github.com/tirogen/go-ethereum/common/mclock" 32 "github.com/tirogen/go-ethereum/log" 33 "github.com/tirogen/go-ethereum/p2p/discover/v5wire" 34 "github.com/tirogen/go-ethereum/p2p/enode" 35 "github.com/tirogen/go-ethereum/p2p/enr" 36 "github.com/tirogen/go-ethereum/p2p/netutil" 37 ) 38 39 const ( 40 lookupRequestLimit = 3 // max requests against a single node during lookup 41 findnodeResultLimit = 16 // applies in FINDNODE handler 42 totalNodesResponseLimit = 5 // applies in waitForNodes 43 44 respTimeoutV5 = 700 * time.Millisecond 45 ) 46 47 // codecV5 is implemented by v5wire.Codec (and testCodec). 48 // 49 // The UDPv5 transport is split into two objects: the codec object deals with 50 // encoding/decoding and with the handshake; the UDPv5 object handles higher-level concerns. 51 type codecV5 interface { 52 // Encode encodes a packet. 53 Encode(enode.ID, string, v5wire.Packet, *v5wire.Whoareyou) ([]byte, v5wire.Nonce, error) 54 55 // Decode decodes a packet. It returns a *v5wire.Unknown packet if decryption fails. 56 // The *enode.Node return value is non-nil when the input contains a handshake response. 57 Decode([]byte, string) (enode.ID, *enode.Node, v5wire.Packet, error) 58 } 59 60 // UDPv5 is the implementation of protocol version 5. 61 type UDPv5 struct { 62 // static fields 63 conn UDPConn 64 tab *Table 65 netrestrict *netutil.Netlist 66 priv *ecdsa.PrivateKey 67 localNode *enode.LocalNode 68 db *enode.DB 69 log log.Logger 70 clock mclock.Clock 71 validSchemes enr.IdentityScheme 72 73 // talkreq handler registry 74 trlock sync.Mutex 75 trhandlers map[string]TalkRequestHandler 76 77 // channels into dispatch 78 packetInCh chan ReadPacket 79 readNextCh chan struct{} 80 callCh chan *callV5 81 callDoneCh chan *callV5 82 respTimeoutCh chan *callTimeout 83 84 // state of dispatch 85 codec codecV5 86 activeCallByNode map[enode.ID]*callV5 87 activeCallByAuth map[v5wire.Nonce]*callV5 88 callQueue map[enode.ID][]*callV5 89 90 // shutdown stuff 91 closeOnce sync.Once 92 closeCtx context.Context 93 cancelCloseCtx context.CancelFunc 94 wg sync.WaitGroup 95 } 96 97 // TalkRequestHandler callback processes a talk request and optionally returns a reply 98 type TalkRequestHandler func(enode.ID, *net.UDPAddr, []byte) []byte 99 100 // callV5 represents a remote procedure call against another node. 101 type callV5 struct { 102 node *enode.Node 103 packet v5wire.Packet 104 responseType byte // expected packet type of response 105 reqid []byte 106 ch chan v5wire.Packet // responses sent here 107 err chan error // errors sent here 108 109 // Valid for active calls only: 110 nonce v5wire.Nonce // nonce of request packet 111 handshakeCount int // # times we attempted handshake for this call 112 challenge *v5wire.Whoareyou // last sent handshake challenge 113 timeout mclock.Timer 114 } 115 116 // callTimeout is the response timeout event of a call. 117 type callTimeout struct { 118 c *callV5 119 timer mclock.Timer 120 } 121 122 // ListenV5 listens on the given connection. 123 func ListenV5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { 124 t, err := newUDPv5(conn, ln, cfg) 125 if err != nil { 126 return nil, err 127 } 128 go t.tab.loop() 129 t.wg.Add(2) 130 go t.readLoop() 131 go t.dispatch() 132 return t, nil 133 } 134 135 // newUDPv5 creates a UDPv5 transport, but doesn't start any goroutines. 136 func newUDPv5(conn UDPConn, ln *enode.LocalNode, cfg Config) (*UDPv5, error) { 137 closeCtx, cancelCloseCtx := context.WithCancel(context.Background()) 138 cfg = cfg.withDefaults() 139 t := &UDPv5{ 140 // static fields 141 conn: conn, 142 localNode: ln, 143 db: ln.Database(), 144 netrestrict: cfg.NetRestrict, 145 priv: cfg.PrivateKey, 146 log: cfg.Log, 147 validSchemes: cfg.ValidSchemes, 148 clock: cfg.Clock, 149 trhandlers: make(map[string]TalkRequestHandler), 150 // channels into dispatch 151 packetInCh: make(chan ReadPacket, 1), 152 readNextCh: make(chan struct{}, 1), 153 callCh: make(chan *callV5), 154 callDoneCh: make(chan *callV5), 155 respTimeoutCh: make(chan *callTimeout), 156 // state of dispatch 157 codec: v5wire.NewCodec(ln, cfg.PrivateKey, cfg.Clock, cfg.V5ProtocolID), 158 activeCallByNode: make(map[enode.ID]*callV5), 159 activeCallByAuth: make(map[v5wire.Nonce]*callV5), 160 callQueue: make(map[enode.ID][]*callV5), 161 // shutdown 162 closeCtx: closeCtx, 163 cancelCloseCtx: cancelCloseCtx, 164 } 165 tab, err := newTable(t, t.db, cfg.Bootnodes, cfg.Log) 166 if err != nil { 167 return nil, err 168 } 169 t.tab = tab 170 return t, nil 171 } 172 173 // Self returns the local node record. 174 func (t *UDPv5) Self() *enode.Node { 175 return t.localNode.Node() 176 } 177 178 // Close shuts down packet processing. 179 func (t *UDPv5) Close() { 180 t.closeOnce.Do(func() { 181 t.cancelCloseCtx() 182 t.conn.Close() 183 t.wg.Wait() 184 t.tab.close() 185 }) 186 } 187 188 // Ping sends a ping message to the given node. 189 func (t *UDPv5) Ping(n *enode.Node) error { 190 _, err := t.ping(n) 191 return err 192 } 193 194 // Resolve searches for a specific node with the given ID and tries to get the most recent 195 // version of the node record for it. It returns n if the node could not be resolved. 196 func (t *UDPv5) Resolve(n *enode.Node) *enode.Node { 197 if intable := t.tab.getNode(n.ID()); intable != nil && intable.Seq() > n.Seq() { 198 n = intable 199 } 200 // Try asking directly. This works if the node is still responding on the endpoint we have. 201 if resp, err := t.RequestENR(n); err == nil { 202 return resp 203 } 204 // Otherwise do a network lookup. 205 result := t.Lookup(n.ID()) 206 for _, rn := range result { 207 if rn.ID() == n.ID() && rn.Seq() > n.Seq() { 208 return rn 209 } 210 } 211 return n 212 } 213 214 // AllNodes returns all the nodes stored in the local table. 215 func (t *UDPv5) AllNodes() []*enode.Node { 216 t.tab.mutex.Lock() 217 defer t.tab.mutex.Unlock() 218 nodes := make([]*enode.Node, 0) 219 220 for _, b := range &t.tab.buckets { 221 for _, n := range b.entries { 222 nodes = append(nodes, unwrapNode(n)) 223 } 224 } 225 return nodes 226 } 227 228 // LocalNode returns the current local node running the 229 // protocol. 230 func (t *UDPv5) LocalNode() *enode.LocalNode { 231 return t.localNode 232 } 233 234 // RegisterTalkHandler adds a handler for 'talk requests'. The handler function is called 235 // whenever a request for the given protocol is received and should return the response 236 // data or nil. 237 func (t *UDPv5) RegisterTalkHandler(protocol string, handler TalkRequestHandler) { 238 t.trlock.Lock() 239 defer t.trlock.Unlock() 240 t.trhandlers[protocol] = handler 241 } 242 243 // TalkRequest sends a talk request to n and waits for a response. 244 func (t *UDPv5) TalkRequest(n *enode.Node, protocol string, request []byte) ([]byte, error) { 245 req := &v5wire.TalkRequest{Protocol: protocol, Message: request} 246 resp := t.call(n, v5wire.TalkResponseMsg, req) 247 defer t.callDone(resp) 248 select { 249 case respMsg := <-resp.ch: 250 return respMsg.(*v5wire.TalkResponse).Message, nil 251 case err := <-resp.err: 252 return nil, err 253 } 254 } 255 256 // RandomNodes returns an iterator that finds random nodes in the DHT. 257 func (t *UDPv5) RandomNodes() enode.Iterator { 258 if t.tab.len() == 0 { 259 // All nodes were dropped, refresh. The very first query will hit this 260 // case and run the bootstrapping logic. 261 <-t.tab.refresh() 262 } 263 264 return newLookupIterator(t.closeCtx, t.newRandomLookup) 265 } 266 267 // Lookup performs a recursive lookup for the given target. 268 // It returns the closest nodes to target. 269 func (t *UDPv5) Lookup(target enode.ID) []*enode.Node { 270 return t.newLookup(t.closeCtx, target).run() 271 } 272 273 // lookupRandom looks up a random target. 274 // This is needed to satisfy the transport interface. 275 func (t *UDPv5) lookupRandom() []*enode.Node { 276 return t.newRandomLookup(t.closeCtx).run() 277 } 278 279 // lookupSelf looks up our own node ID. 280 // This is needed to satisfy the transport interface. 281 func (t *UDPv5) lookupSelf() []*enode.Node { 282 return t.newLookup(t.closeCtx, t.Self().ID()).run() 283 } 284 285 func (t *UDPv5) newRandomLookup(ctx context.Context) *lookup { 286 var target enode.ID 287 crand.Read(target[:]) 288 return t.newLookup(ctx, target) 289 } 290 291 func (t *UDPv5) newLookup(ctx context.Context, target enode.ID) *lookup { 292 return newLookup(ctx, t.tab, target, func(n *node) ([]*node, error) { 293 return t.lookupWorker(n, target) 294 }) 295 } 296 297 // lookupWorker performs FINDNODE calls against a single node during lookup. 298 func (t *UDPv5) lookupWorker(destNode *node, target enode.ID) ([]*node, error) { 299 var ( 300 dists = lookupDistances(target, destNode.ID()) 301 nodes = nodesByDistance{target: target} 302 err error 303 ) 304 var r []*enode.Node 305 r, err = t.findnode(unwrapNode(destNode), dists) 306 if errors.Is(err, errClosed) { 307 return nil, err 308 } 309 for _, n := range r { 310 if n.ID() != t.Self().ID() { 311 nodes.push(wrapNode(n), findnodeResultLimit) 312 } 313 } 314 return nodes.entries, err 315 } 316 317 // lookupDistances computes the distance parameter for FINDNODE calls to dest. 318 // It chooses distances adjacent to logdist(target, dest), e.g. for a target 319 // with logdist(target, dest) = 255 the result is [255, 256, 254]. 320 func lookupDistances(target, dest enode.ID) (dists []uint) { 321 td := enode.LogDist(target, dest) 322 dists = append(dists, uint(td)) 323 for i := 1; len(dists) < lookupRequestLimit; i++ { 324 if td+i <= 256 { 325 dists = append(dists, uint(td+i)) 326 } 327 if td-i > 0 { 328 dists = append(dists, uint(td-i)) 329 } 330 } 331 return dists 332 } 333 334 // ping calls PING on a node and waits for a PONG response. 335 func (t *UDPv5) ping(n *enode.Node) (uint64, error) { 336 req := &v5wire.Ping{ENRSeq: t.localNode.Node().Seq()} 337 resp := t.call(n, v5wire.PongMsg, req) 338 defer t.callDone(resp) 339 340 select { 341 case pong := <-resp.ch: 342 return pong.(*v5wire.Pong).ENRSeq, nil 343 case err := <-resp.err: 344 return 0, err 345 } 346 } 347 348 // RequestENR requests n's record. 349 func (t *UDPv5) RequestENR(n *enode.Node) (*enode.Node, error) { 350 nodes, err := t.findnode(n, []uint{0}) 351 if err != nil { 352 return nil, err 353 } 354 if len(nodes) != 1 { 355 return nil, fmt.Errorf("%d nodes in response for distance zero", len(nodes)) 356 } 357 return nodes[0], nil 358 } 359 360 // findnode calls FINDNODE on a node and waits for responses. 361 func (t *UDPv5) findnode(n *enode.Node, distances []uint) ([]*enode.Node, error) { 362 resp := t.call(n, v5wire.NodesMsg, &v5wire.Findnode{Distances: distances}) 363 return t.waitForNodes(resp, distances) 364 } 365 366 // waitForNodes waits for NODES responses to the given call. 367 func (t *UDPv5) waitForNodes(c *callV5, distances []uint) ([]*enode.Node, error) { 368 defer t.callDone(c) 369 370 var ( 371 nodes []*enode.Node 372 seen = make(map[enode.ID]struct{}) 373 received, total = 0, -1 374 ) 375 for { 376 select { 377 case responseP := <-c.ch: 378 response := responseP.(*v5wire.Nodes) 379 for _, record := range response.Nodes { 380 node, err := t.verifyResponseNode(c, record, distances, seen) 381 if err != nil { 382 t.log.Debug("Invalid record in "+response.Name(), "id", c.node.ID(), "err", err) 383 continue 384 } 385 nodes = append(nodes, node) 386 } 387 if total == -1 { 388 total = min(int(response.Total), totalNodesResponseLimit) 389 } 390 if received++; received == total { 391 return nodes, nil 392 } 393 case err := <-c.err: 394 return nodes, err 395 } 396 } 397 } 398 399 // verifyResponseNode checks validity of a record in a NODES response. 400 func (t *UDPv5) verifyResponseNode(c *callV5, r *enr.Record, distances []uint, seen map[enode.ID]struct{}) (*enode.Node, error) { 401 node, err := enode.New(t.validSchemes, r) 402 if err != nil { 403 return nil, err 404 } 405 if err := netutil.CheckRelayIP(c.node.IP(), node.IP()); err != nil { 406 return nil, err 407 } 408 if t.netrestrict != nil && !t.netrestrict.Contains(node.IP()) { 409 return nil, errors.New("not contained in netrestrict list") 410 } 411 if c.node.UDP() <= 1024 { 412 return nil, errLowPort 413 } 414 if distances != nil { 415 nd := enode.LogDist(c.node.ID(), node.ID()) 416 if !containsUint(uint(nd), distances) { 417 return nil, errors.New("does not match any requested distance") 418 } 419 } 420 if _, ok := seen[node.ID()]; ok { 421 return nil, fmt.Errorf("duplicate record") 422 } 423 seen[node.ID()] = struct{}{} 424 return node, nil 425 } 426 427 func containsUint(x uint, xs []uint) bool { 428 for _, v := range xs { 429 if x == v { 430 return true 431 } 432 } 433 return false 434 } 435 436 // call sends the given call and sets up a handler for response packets (of message type 437 // responseType). Responses are dispatched to the call's response channel. 438 func (t *UDPv5) call(node *enode.Node, responseType byte, packet v5wire.Packet) *callV5 { 439 c := &callV5{ 440 node: node, 441 packet: packet, 442 responseType: responseType, 443 reqid: make([]byte, 8), 444 ch: make(chan v5wire.Packet, 1), 445 err: make(chan error, 1), 446 } 447 // Assign request ID. 448 crand.Read(c.reqid) 449 packet.SetRequestID(c.reqid) 450 // Send call to dispatch. 451 select { 452 case t.callCh <- c: 453 case <-t.closeCtx.Done(): 454 c.err <- errClosed 455 } 456 return c 457 } 458 459 // callDone tells dispatch that the active call is done. 460 func (t *UDPv5) callDone(c *callV5) { 461 // This needs a loop because further responses may be incoming until the 462 // send to callDoneCh has completed. Such responses need to be discarded 463 // in order to avoid blocking the dispatch loop. 464 for { 465 select { 466 case <-c.ch: 467 // late response, discard. 468 case <-c.err: 469 // late error, discard. 470 case t.callDoneCh <- c: 471 return 472 case <-t.closeCtx.Done(): 473 return 474 } 475 } 476 } 477 478 // dispatch runs in its own goroutine, handles incoming packets and deals with calls. 479 // 480 // For any destination node there is at most one 'active call', stored in the t.activeCall* 481 // maps. A call is made active when it is sent. The active call can be answered by a 482 // matching response, in which case c.ch receives the response; or by timing out, in which case 483 // c.err receives the error. When the function that created the call signals the active 484 // call is done through callDone, the next call from the call queue is started. 485 // 486 // Calls may also be answered by a WHOAREYOU packet referencing the call packet's authTag. 487 // When that happens the call is simply re-sent to complete the handshake. We allow one 488 // handshake attempt per call. 489 func (t *UDPv5) dispatch() { 490 defer t.wg.Done() 491 492 // Arm first read. 493 t.readNextCh <- struct{}{} 494 495 for { 496 select { 497 case c := <-t.callCh: 498 id := c.node.ID() 499 t.callQueue[id] = append(t.callQueue[id], c) 500 t.sendNextCall(id) 501 502 case ct := <-t.respTimeoutCh: 503 active := t.activeCallByNode[ct.c.node.ID()] 504 if ct.c == active && ct.timer == active.timeout { 505 ct.c.err <- errTimeout 506 } 507 508 case c := <-t.callDoneCh: 509 id := c.node.ID() 510 active := t.activeCallByNode[id] 511 if active != c { 512 panic("BUG: callDone for inactive call") 513 } 514 c.timeout.Stop() 515 delete(t.activeCallByAuth, c.nonce) 516 delete(t.activeCallByNode, id) 517 t.sendNextCall(id) 518 519 case p := <-t.packetInCh: 520 t.handlePacket(p.Data, p.Addr) 521 // Arm next read. 522 t.readNextCh <- struct{}{} 523 524 case <-t.closeCtx.Done(): 525 close(t.readNextCh) 526 for id, queue := range t.callQueue { 527 for _, c := range queue { 528 c.err <- errClosed 529 } 530 delete(t.callQueue, id) 531 } 532 for id, c := range t.activeCallByNode { 533 c.err <- errClosed 534 delete(t.activeCallByNode, id) 535 delete(t.activeCallByAuth, c.nonce) 536 } 537 return 538 } 539 } 540 } 541 542 // startResponseTimeout sets the response timer for a call. 543 func (t *UDPv5) startResponseTimeout(c *callV5) { 544 if c.timeout != nil { 545 c.timeout.Stop() 546 } 547 var ( 548 timer mclock.Timer 549 done = make(chan struct{}) 550 ) 551 timer = t.clock.AfterFunc(respTimeoutV5, func() { 552 <-done 553 select { 554 case t.respTimeoutCh <- &callTimeout{c, timer}: 555 case <-t.closeCtx.Done(): 556 } 557 }) 558 c.timeout = timer 559 close(done) 560 } 561 562 // sendNextCall sends the next call in the call queue if there is no active call. 563 func (t *UDPv5) sendNextCall(id enode.ID) { 564 queue := t.callQueue[id] 565 if len(queue) == 0 || t.activeCallByNode[id] != nil { 566 return 567 } 568 t.activeCallByNode[id] = queue[0] 569 t.sendCall(t.activeCallByNode[id]) 570 if len(queue) == 1 { 571 delete(t.callQueue, id) 572 } else { 573 copy(queue, queue[1:]) 574 t.callQueue[id] = queue[:len(queue)-1] 575 } 576 } 577 578 // sendCall encodes and sends a request packet to the call's recipient node. 579 // This performs a handshake if needed. 580 func (t *UDPv5) sendCall(c *callV5) { 581 // The call might have a nonce from a previous handshake attempt. Remove the entry for 582 // the old nonce because we're about to generate a new nonce for this call. 583 if c.nonce != (v5wire.Nonce{}) { 584 delete(t.activeCallByAuth, c.nonce) 585 } 586 587 addr := &net.UDPAddr{IP: c.node.IP(), Port: c.node.UDP()} 588 newNonce, _ := t.send(c.node.ID(), addr, c.packet, c.challenge) 589 c.nonce = newNonce 590 t.activeCallByAuth[newNonce] = c 591 t.startResponseTimeout(c) 592 } 593 594 // sendResponse sends a response packet to the given node. 595 // This doesn't trigger a handshake even if no keys are available. 596 func (t *UDPv5) sendResponse(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet) error { 597 _, err := t.send(toID, toAddr, packet, nil) 598 return err 599 } 600 601 // send sends a packet to the given node. 602 func (t *UDPv5) send(toID enode.ID, toAddr *net.UDPAddr, packet v5wire.Packet, c *v5wire.Whoareyou) (v5wire.Nonce, error) { 603 addr := toAddr.String() 604 enc, nonce, err := t.codec.Encode(toID, addr, packet, c) 605 if err != nil { 606 t.log.Warn(">> "+packet.Name(), "id", toID, "addr", addr, "err", err) 607 return nonce, err 608 } 609 _, err = t.conn.WriteToUDP(enc, toAddr) 610 t.log.Trace(">> "+packet.Name(), "id", toID, "addr", addr) 611 return nonce, err 612 } 613 614 // readLoop runs in its own goroutine and reads packets from the network. 615 func (t *UDPv5) readLoop() { 616 defer t.wg.Done() 617 618 buf := make([]byte, maxPacketSize) 619 for range t.readNextCh { 620 nbytes, from, err := t.conn.ReadFromUDP(buf) 621 if netutil.IsTemporaryError(err) { 622 // Ignore temporary read errors. 623 t.log.Debug("Temporary UDP read error", "err", err) 624 continue 625 } else if err != nil { 626 // Shut down the loop for permanent errors. 627 if !errors.Is(err, io.EOF) { 628 t.log.Debug("UDP read error", "err", err) 629 } 630 return 631 } 632 t.dispatchReadPacket(from, buf[:nbytes]) 633 } 634 } 635 636 // dispatchReadPacket sends a packet into the dispatch loop. 637 func (t *UDPv5) dispatchReadPacket(from *net.UDPAddr, content []byte) bool { 638 select { 639 case t.packetInCh <- ReadPacket{content, from}: 640 return true 641 case <-t.closeCtx.Done(): 642 return false 643 } 644 } 645 646 // handlePacket decodes and processes an incoming packet from the network. 647 func (t *UDPv5) handlePacket(rawpacket []byte, fromAddr *net.UDPAddr) error { 648 addr := fromAddr.String() 649 fromID, fromNode, packet, err := t.codec.Decode(rawpacket, addr) 650 if err != nil { 651 t.log.Debug("Bad discv5 packet", "id", fromID, "addr", addr, "err", err) 652 return err 653 } 654 if fromNode != nil { 655 // Handshake succeeded, add to table. 656 t.tab.addSeenNode(wrapNode(fromNode)) 657 } 658 if packet.Kind() != v5wire.WhoareyouPacket { 659 // WHOAREYOU logged separately to report errors. 660 t.log.Trace("<< "+packet.Name(), "id", fromID, "addr", addr) 661 } 662 t.handle(packet, fromID, fromAddr) 663 return nil 664 } 665 666 // handleCallResponse dispatches a response packet to the call waiting for it. 667 func (t *UDPv5) handleCallResponse(fromID enode.ID, fromAddr *net.UDPAddr, p v5wire.Packet) bool { 668 ac := t.activeCallByNode[fromID] 669 if ac == nil || !bytes.Equal(p.RequestID(), ac.reqid) { 670 t.log.Debug(fmt.Sprintf("Unsolicited/late %s response", p.Name()), "id", fromID, "addr", fromAddr) 671 return false 672 } 673 if !fromAddr.IP.Equal(ac.node.IP()) || fromAddr.Port != ac.node.UDP() { 674 t.log.Debug(fmt.Sprintf("%s from wrong endpoint", p.Name()), "id", fromID, "addr", fromAddr) 675 return false 676 } 677 if p.Kind() != ac.responseType { 678 t.log.Debug(fmt.Sprintf("Wrong discv5 response type %s", p.Name()), "id", fromID, "addr", fromAddr) 679 return false 680 } 681 t.startResponseTimeout(ac) 682 ac.ch <- p 683 return true 684 } 685 686 // getNode looks for a node record in table and database. 687 func (t *UDPv5) getNode(id enode.ID) *enode.Node { 688 if n := t.tab.getNode(id); n != nil { 689 return n 690 } 691 if n := t.localNode.Database().Node(id); n != nil { 692 return n 693 } 694 return nil 695 } 696 697 // handle processes incoming packets according to their message type. 698 func (t *UDPv5) handle(p v5wire.Packet, fromID enode.ID, fromAddr *net.UDPAddr) { 699 switch p := p.(type) { 700 case *v5wire.Unknown: 701 t.handleUnknown(p, fromID, fromAddr) 702 case *v5wire.Whoareyou: 703 t.handleWhoareyou(p, fromID, fromAddr) 704 case *v5wire.Ping: 705 t.handlePing(p, fromID, fromAddr) 706 case *v5wire.Pong: 707 if t.handleCallResponse(fromID, fromAddr, p) { 708 t.localNode.UDPEndpointStatement(fromAddr, &net.UDPAddr{IP: p.ToIP, Port: int(p.ToPort)}) 709 } 710 case *v5wire.Findnode: 711 t.handleFindnode(p, fromID, fromAddr) 712 case *v5wire.Nodes: 713 t.handleCallResponse(fromID, fromAddr, p) 714 case *v5wire.TalkRequest: 715 t.handleTalkRequest(p, fromID, fromAddr) 716 case *v5wire.TalkResponse: 717 t.handleCallResponse(fromID, fromAddr, p) 718 } 719 } 720 721 // handleUnknown initiates a handshake by responding with WHOAREYOU. 722 func (t *UDPv5) handleUnknown(p *v5wire.Unknown, fromID enode.ID, fromAddr *net.UDPAddr) { 723 challenge := &v5wire.Whoareyou{Nonce: p.Nonce} 724 crand.Read(challenge.IDNonce[:]) 725 if n := t.getNode(fromID); n != nil { 726 challenge.Node = n 727 challenge.RecordSeq = n.Seq() 728 } 729 t.sendResponse(fromID, fromAddr, challenge) 730 } 731 732 var ( 733 errChallengeNoCall = errors.New("no matching call") 734 errChallengeTwice = errors.New("second handshake") 735 ) 736 737 // handleWhoareyou resends the active call as a handshake packet. 738 func (t *UDPv5) handleWhoareyou(p *v5wire.Whoareyou, fromID enode.ID, fromAddr *net.UDPAddr) { 739 c, err := t.matchWithCall(fromID, p.Nonce) 740 if err != nil { 741 t.log.Debug("Invalid "+p.Name(), "addr", fromAddr, "err", err) 742 return 743 } 744 745 // Resend the call that was answered by WHOAREYOU. 746 t.log.Trace("<< "+p.Name(), "id", c.node.ID(), "addr", fromAddr) 747 c.handshakeCount++ 748 c.challenge = p 749 p.Node = c.node 750 t.sendCall(c) 751 } 752 753 // matchWithCall checks whether a handshake attempt matches the active call. 754 func (t *UDPv5) matchWithCall(fromID enode.ID, nonce v5wire.Nonce) (*callV5, error) { 755 c := t.activeCallByAuth[nonce] 756 if c == nil { 757 return nil, errChallengeNoCall 758 } 759 if c.handshakeCount > 0 { 760 return nil, errChallengeTwice 761 } 762 return c, nil 763 } 764 765 // handlePing sends a PONG response. 766 func (t *UDPv5) handlePing(p *v5wire.Ping, fromID enode.ID, fromAddr *net.UDPAddr) { 767 remoteIP := fromAddr.IP 768 // Handle IPv4 mapped IPv6 addresses in the 769 // event the local node is binded to an 770 // ipv6 interface. 771 if remoteIP.To4() != nil { 772 remoteIP = remoteIP.To4() 773 } 774 t.sendResponse(fromID, fromAddr, &v5wire.Pong{ 775 ReqID: p.ReqID, 776 ToIP: remoteIP, 777 ToPort: uint16(fromAddr.Port), 778 ENRSeq: t.localNode.Node().Seq(), 779 }) 780 } 781 782 // handleFindnode returns nodes to the requester. 783 func (t *UDPv5) handleFindnode(p *v5wire.Findnode, fromID enode.ID, fromAddr *net.UDPAddr) { 784 nodes := t.collectTableNodes(fromAddr.IP, p.Distances, findnodeResultLimit) 785 for _, resp := range packNodes(p.ReqID, nodes) { 786 t.sendResponse(fromID, fromAddr, resp) 787 } 788 } 789 790 // collectTableNodes creates a FINDNODE result set for the given distances. 791 func (t *UDPv5) collectTableNodes(rip net.IP, distances []uint, limit int) []*enode.Node { 792 var nodes []*enode.Node 793 var processed = make(map[uint]struct{}) 794 for _, dist := range distances { 795 // Reject duplicate / invalid distances. 796 _, seen := processed[dist] 797 if seen || dist > 256 { 798 continue 799 } 800 801 // Get the nodes. 802 var bn []*enode.Node 803 if dist == 0 { 804 bn = []*enode.Node{t.Self()} 805 } else if dist <= 256 { 806 t.tab.mutex.Lock() 807 bn = unwrapNodes(t.tab.bucketAtDistance(int(dist)).entries) 808 t.tab.mutex.Unlock() 809 } 810 processed[dist] = struct{}{} 811 812 // Apply some pre-checks to avoid sending invalid nodes. 813 for _, n := range bn { 814 // TODO livenessChecks > 1 815 if netutil.CheckRelayIP(rip, n.IP()) != nil { 816 continue 817 } 818 nodes = append(nodes, n) 819 if len(nodes) >= limit { 820 return nodes 821 } 822 } 823 } 824 return nodes 825 } 826 827 // packNodes creates NODES response packets for the given node list. 828 func packNodes(reqid []byte, nodes []*enode.Node) []*v5wire.Nodes { 829 if len(nodes) == 0 { 830 return []*v5wire.Nodes{{ReqID: reqid, Total: 1}} 831 } 832 833 // This limit represents the available space for nodes in output packets. Maximum 834 // packet size is 1280, and out of this ~80 bytes will be taken up by the packet 835 // frame. So limiting to 1000 bytes here leaves 200 bytes for other fields of the 836 // NODES message, which is a lot. 837 const sizeLimit = 1000 838 839 var resp []*v5wire.Nodes 840 for len(nodes) > 0 { 841 p := &v5wire.Nodes{ReqID: reqid} 842 size := uint64(0) 843 for len(nodes) > 0 { 844 r := nodes[0].Record() 845 if size += r.Size(); size > sizeLimit { 846 break 847 } 848 p.Nodes = append(p.Nodes, r) 849 nodes = nodes[1:] 850 } 851 resp = append(resp, p) 852 } 853 for _, msg := range resp { 854 msg.Total = uint8(len(resp)) 855 } 856 return resp 857 } 858 859 // handleTalkRequest runs the talk request handler of the requested protocol. 860 func (t *UDPv5) handleTalkRequest(p *v5wire.TalkRequest, fromID enode.ID, fromAddr *net.UDPAddr) { 861 t.trlock.Lock() 862 handler := t.trhandlers[p.Protocol] 863 t.trlock.Unlock() 864 865 var response []byte 866 if handler != nil { 867 response = handler(fromID, fromAddr, p.Message) 868 } 869 resp := &v5wire.TalkResponse{ReqID: p.ReqID, Message: response} 870 t.sendResponse(fromID, fromAddr, resp) 871 }