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