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