github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/discover/udp.go (about) 1 // Copyright 2015 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 "container/list" 22 "crypto/ecdsa" 23 "errors" 24 "fmt" 25 "net" 26 "time" 27 28 "github.com/ethereumproject/go-ethereum/crypto" 29 "github.com/ethereumproject/go-ethereum/logger" 30 "github.com/ethereumproject/go-ethereum/logger/glog" 31 "github.com/ethereumproject/go-ethereum/p2p/distip" 32 "github.com/ethereumproject/go-ethereum/p2p/nat" 33 "github.com/ethereumproject/go-ethereum/rlp" 34 ) 35 36 const Version = 4 37 38 // Errors 39 var ( 40 errPacketTooSmall = errors.New("too small") 41 errBadHash = errors.New("bad hash") 42 errExpired = errors.New("expired") 43 errUnsolicitedReply = errors.New("unsolicited reply") 44 errUnknownNode = errors.New("unknown node") 45 errReservedAddress = errors.New("reserved address neighbor from non-reserved source") 46 errInvalidIp = errors.New("invalid ip") 47 errTimeout = errors.New("RPC timeout") 48 errClockWarp = errors.New("reply deadline too far in the future") 49 errClosed = errors.New("socket closed") 50 51 // Note: golang/net.IP provides some similar functionality via #IsLinkLocalUnicast, ...Multicast, etc. 52 // I would rather duplicate the information in a unified and comprehensive system than 53 // patch-in with a couple available library methods. 54 // I expect many of these occasions will be very unlikely. 55 // 56 // IPv4 57 Ipv4ReservedRangeThis = [2]net.IP{net.ParseIP("0.0.0.0"), net.ParseIP("0.255.255.255")} 58 Ipv4ReservedRangePrivateNetwork = [2]net.IP{net.ParseIP("10.0.0.0"), net.ParseIP("10.255.255.255")} 59 ipv4ReservedRangeProviderSubscriber = [2]net.IP{net.ParseIP("100.64.0.0"), net.ParseIP("100.127.255.255")} 60 Ipv4ReservedRangeLoopback = [2]net.IP{net.ParseIP("127.0.0.0"), net.ParseIP("127.255.255.255")} 61 ipv4ReservedRangeLinkLocal = [2]net.IP{net.ParseIP("169.254.0.0"), net.ParseIP("169.254.255.255")} 62 ipv4ReservedRangeLocalPrivate1 = [2]net.IP{net.ParseIP("172.16.0.0"), net.ParseIP("172.31.255.255")} 63 ipv4ReservedRangeSpecialPurpose = [2]net.IP{net.ParseIP("192.0.0.0"), net.ParseIP("192.0.0.255")} 64 ipv4ReservedRangeTestNet1 = [2]net.IP{net.ParseIP("192.0.2.0"), net.ParseIP("192.0.2.255")} 65 ipv4ReservedRange6to4 = [2]net.IP{net.ParseIP("192.88.99.0"), net.ParseIP("192.88.99.255")} 66 Ipv4ReservedRangeLocalPrivate2 = [2]net.IP{net.ParseIP("192.168.0.0"), net.ParseIP("192.168.255.255")} 67 ipv4ReservedRangeSubnets = [2]net.IP{net.ParseIP("198.18.0.0"), net.ParseIP("198.19.255.255")} 68 ipv4ReservedRangeTestNet2 = [2]net.IP{net.ParseIP("198.51.100.0"), net.ParseIP("198.51.100.255")} 69 ipv4ReservedRangeTestNet3 = [2]net.IP{net.ParseIP("203.0.113.0"), net.ParseIP("203.0.113.255")} 70 ipv4ReservedRangeMulticast = [2]net.IP{net.ParseIP("224.0.0.0"), net.ParseIP("239.255.255.255")} 71 ipv4ReservedRangeFuture = [2]net.IP{net.ParseIP("240.0.0.0"), net.ParseIP("255.255.255.254")} 72 ipv4ReservedRangeLimitedBroadcast = [2]net.IP{net.ParseIP("255.255.255.255"), net.ParseIP("255.255.255.255")} 73 74 // IPv6 75 ipv6ReservedRangeUnspecified = [2]net.IP{net.ParseIP("::"), net.ParseIP("::")} 76 Ipv6ReservedRangeLoopback = [2]net.IP{net.ParseIP("::1"), net.ParseIP("::1")} 77 ipv6ReservedRangeDocumentation = [2]net.IP{net.ParseIP("2001:db8::"), net.ParseIP("2001:db8:ffff:ffff:ffff:ffff:ffff:ffff")} 78 ipv6ReservedRange6to4 = [2]net.IP{net.ParseIP("2002::"), net.ParseIP("2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff")} 79 ipv6ReservedRangeUniqueLocal = [2]net.IP{net.ParseIP("fc00::"), net.ParseIP("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")} 80 ipv6ReservedRangeLinkLocal = [2]net.IP{net.ParseIP("fe80::"), net.ParseIP("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")} 81 ipv6ReservedRangeMulticast = [2]net.IP{net.ParseIP("ff00::"), net.ParseIP("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")} 82 ) 83 84 // Timeouts 85 const ( 86 respTimeout = 500 * time.Millisecond 87 expiration = 20 * time.Second 88 89 ntpFailureThreshold = 32 // Continuous timeouts after which to check NTP 90 ntpWarningCooldown = 10 * time.Minute // Minimum amount of time to pass before repeating NTP warning 91 driftThreshold = 10 * time.Second // Allowed clock drift before warning user 92 ) 93 94 // RPC packet types 95 const ( 96 pingPacket = iota + 1 // zero is 'reserved' 97 pongPacket 98 findnodePacket 99 neighborsPacket 100 ) 101 102 // RPC request structures 103 type ( 104 ping struct { 105 Version uint 106 From, To rpcEndpoint 107 Expiration uint64 108 // Ignore additional fields (for forward compatibility). 109 Rest []rlp.RawValue `rlp:"tail"` 110 } 111 112 // pong is the reply to ping. 113 pong struct { 114 // This field should mirror the UDP envelope address 115 // of the ping packet, which provides a way to discover the 116 // the external address (after NAT). 117 To rpcEndpoint 118 119 ReplyTok []byte // This contains the hash of the ping packet. 120 Expiration uint64 // Absolute timestamp at which the packet becomes invalid. 121 // Ignore additional fields (for forward compatibility). 122 Rest []rlp.RawValue `rlp:"tail"` 123 } 124 125 // findnode is a query for nodes close to the given target. 126 findnode struct { 127 Target NodeID // doesn't need to be an actual public key 128 Expiration uint64 129 // Ignore additional fields (for forward compatibility). 130 Rest []rlp.RawValue `rlp:"tail"` 131 } 132 133 // reply to findnode 134 neighbors struct { 135 Nodes []rpcNode 136 Expiration uint64 137 // Ignore additional fields (for forward compatibility). 138 Rest []rlp.RawValue `rlp:"tail"` 139 } 140 141 rpcNode struct { 142 IP net.IP // len 4 for IPv4 or 16 for IPv6 143 UDP uint16 // for discovery protocol 144 TCP uint16 // for RLPx protocol 145 ID NodeID 146 } 147 148 rpcEndpoint struct { 149 IP net.IP // len 4 for IPv4 or 16 for IPv6 150 UDP uint16 // for discovery protocol 151 TCP uint16 // for RLPx protocol 152 } 153 ) 154 155 func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint { 156 ip := addr.IP.To4() 157 if ip == nil { 158 ip = addr.IP.To16() 159 } 160 return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort} 161 } 162 163 func (t *udp) nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) { 164 if rn.UDP <= 1024 { 165 return nil, errors.New("low port") 166 } 167 if err := distip.CheckRelayIP(sender.IP, rn.IP); err != nil { 168 return nil, err 169 } 170 if t.netrestrict != nil && !t.netrestrict.Contains(rn.IP) { 171 return nil, errors.New("not contained in netrestrict whitelist") 172 } 173 n := NewNode(rn.ID, rn.IP, rn.UDP, rn.TCP) 174 err := n.validateComplete() 175 return n, err 176 } 177 178 func nodeToRPC(n *Node) rpcNode { 179 return rpcNode{ID: n.ID, IP: n.IP, UDP: n.UDP, TCP: n.TCP} 180 } 181 182 type packet interface { 183 handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error 184 } 185 186 type conn interface { 187 ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) 188 WriteToUDP(b []byte, addr *net.UDPAddr) (n int, err error) 189 Close() error 190 LocalAddr() net.Addr 191 } 192 193 // udp implements the RPC protocol. 194 type udp struct { 195 conn conn 196 netrestrict *distip.Netlist 197 priv *ecdsa.PrivateKey 198 ourEndpoint rpcEndpoint 199 200 addpending chan *pending 201 gotreply chan reply 202 203 closing chan struct{} 204 205 *Table 206 } 207 208 // pending represents a pending reply. 209 // 210 // some implementations of the protocol wish to send more than one 211 // reply packet to findnode. in general, any neighbors packet cannot 212 // be matched up with a specific findnode packet. 213 // 214 // our implementation handles this by storing a callback function for 215 // each pending reply. incoming packets from a node are dispatched 216 // to all the callback functions for that node. 217 type pending struct { 218 // these fields must match in the reply. 219 from NodeID 220 ptype byte 221 222 // time when the request must complete 223 deadline time.Time 224 225 // callback is called when a matching reply arrives. if it returns 226 // true, the callback is removed from the pending reply queue. 227 // if it returns false, the reply is considered incomplete and 228 // the callback will be invoked again for the next matching reply. 229 callback func(resp interface{}) (done bool) 230 231 // errc receives nil when the callback indicates completion or an 232 // error if no further reply is received within the timeout. 233 errc chan<- error 234 } 235 236 type reply struct { 237 from NodeID 238 ptype byte 239 data interface{} 240 // loop indicates whether there was 241 // a matching request by sending on this channel. 242 matched chan<- bool 243 } 244 245 // ListenUDP returns a new table that listens for UDP packets on laddr. 246 func ListenUDP(priv *ecdsa.PrivateKey, laddr string, natm nat.Interface, nodeDBPath string) (*Table, error) { 247 addr, err := net.ResolveUDPAddr("udp", laddr) 248 if err != nil { 249 return nil, err 250 } 251 conn, err := net.ListenUDP("udp", addr) 252 if err != nil { 253 return nil, err 254 } 255 tab, _, err := newUDP(priv, conn, natm, nodeDBPath) 256 if err != nil { 257 return nil, err 258 } 259 glog.V(logger.Info).Infoln("Listening,", tab.self) 260 glog.D(logger.Warn).Infoln("UDP listening. Client enode:", logger.ColorGreen(tab.self.String())) 261 262 return tab, nil 263 } 264 265 func newUDP(priv *ecdsa.PrivateKey, c conn, natm nat.Interface, nodeDBPath string) (*Table, *udp, error) { 266 udp := &udp{ 267 conn: c, 268 priv: priv, 269 closing: make(chan struct{}), 270 gotreply: make(chan reply), 271 addpending: make(chan *pending), 272 } 273 realaddr := c.LocalAddr().(*net.UDPAddr) 274 if natm != nil { 275 if !realaddr.IP.IsLoopback() { 276 go nat.Map(natm, udp.closing, "udp", realaddr.Port, realaddr.Port, "ethereum discovery") 277 } 278 // TODO: react to external IP changes over time. 279 if ext, err := natm.ExternalIP(); err == nil { 280 realaddr = &net.UDPAddr{IP: ext, Port: realaddr.Port} 281 } 282 } 283 // TODO: separate TCP port 284 udp.ourEndpoint = makeEndpoint(realaddr, uint16(realaddr.Port)) 285 tab, err := newTable(udp, PubkeyID(&priv.PublicKey), realaddr, nodeDBPath) 286 if err != nil { 287 return nil, nil, err 288 } 289 udp.Table = tab 290 291 go udp.loop() 292 go udp.readLoop() 293 return udp.Table, udp, nil 294 } 295 296 func (t *udp) close() { 297 close(t.closing) 298 t.conn.Close() 299 // TODO: wait for the loops to end. 300 } 301 302 // ping sends a ping message to the given node and waits for a reply. 303 func (t *udp) ping(toid NodeID, toaddr *net.UDPAddr) error { 304 // TODO: maybe check for ReplyTo field in callback to measure RTT 305 errc := t.pending(toid, pongPacket, func(interface{}) bool { return true }) 306 t.send(toaddr, pingPacket, ping{ 307 Version: Version, 308 From: t.ourEndpoint, 309 To: makeEndpoint(toaddr, 0), // TODO: maybe use known TCP port from DB 310 Expiration: uint64(time.Now().Add(expiration).Unix()), 311 }) 312 return <-errc 313 } 314 315 func (t *udp) waitping(from NodeID) error { 316 return <-t.pending(from, pingPacket, func(interface{}) bool { return true }) 317 } 318 319 // findnode sends a findnode request to the given node and waits until 320 // the node has sent up to k neighbors. 321 func (t *udp) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) { 322 nodes := make([]*Node, 0, bucketSize) 323 nreceived := 0 324 errc := t.pending(toid, neighborsPacket, func(r interface{}) bool { 325 reply := r.(*neighbors) 326 for _, rn := range reply.Nodes { 327 nreceived++ 328 if n, err := t.nodeFromRPC(toaddr, rn); err == nil { 329 nodes = append(nodes, n) 330 } 331 } 332 return nreceived >= bucketSize 333 }) 334 t.send(toaddr, findnodePacket, findnode{ 335 Target: target, 336 Expiration: uint64(time.Now().Add(expiration).Unix()), 337 }) 338 err := <-errc 339 340 // remove nodes from *neighbors response 341 // where the originating address (toaddr) is *not* reserved and the given neighbor is reserved. 342 // This prevents irrelevant private network addresses from causing 343 // attempted discoveries on reserved ips that are not on 344 // our node's network. 345 // > https://en.wikipedia.org/wiki/Reserved_IP_addresses 346 // > https://github.com/ethereumproject/go-ethereum/issues/283 347 // > https://tools.ietf.org/html/rfc5737 348 // > https://tools.ietf.org/html/rfc3849 349 if !isReserved(toaddr.IP) { 350 var okNodes []*Node 351 for _, n := range nodes { 352 if isReserved(n.IP) { 353 glog.V(logger.Detail).Warnf("%v: removing from neighbors: toaddr: %v, id: %v, ip: %v", errReservedAddress, toaddr, n.ID, n.IP) 354 continue 355 } 356 okNodes = append(okNodes, n) 357 } 358 nodes = okNodes 359 } 360 361 return nodes, err 362 } 363 364 // pending adds a reply callback to the pending reply queue. 365 // see the documentation of type pending for a detailed explanation. 366 func (t *udp) pending(id NodeID, ptype byte, callback func(interface{}) bool) <-chan error { 367 ch := make(chan error, 1) 368 p := &pending{from: id, ptype: ptype, callback: callback, errc: ch} 369 select { 370 case t.addpending <- p: 371 // loop will handle it 372 case <-t.closing: 373 ch <- errClosed 374 } 375 return ch 376 } 377 378 func (t *udp) handleReply(from NodeID, ptype byte, req packet) bool { 379 matched := make(chan bool, 1) 380 select { 381 case t.gotreply <- reply{from, ptype, req, matched}: 382 // loop will handle it 383 return <-matched 384 case <-t.closing: 385 return false 386 } 387 } 388 389 // loop runs in its own goroutine. it keeps track of 390 // the refresh timer and the pending reply queue. 391 func (t *udp) loop() { 392 var ( 393 plist = list.New() 394 timeout = time.NewTimer(0) 395 nextTimeout *pending // head of plist when timeout was last reset 396 contTimeouts = 0 // number of continuous timeouts to do NTP checks 397 ntpWarnTime = time.Unix(0, 0) 398 ) 399 <-timeout.C // ignore first timeout 400 defer timeout.Stop() 401 402 resetTimeout := func() { 403 if plist.Front() == nil || nextTimeout == plist.Front().Value { 404 return 405 } 406 // Start the timer so it fires when the next pending reply has expired. 407 now := time.Now() 408 for el := plist.Front(); el != nil; el = el.Next() { 409 nextTimeout = el.Value.(*pending) 410 if dist := nextTimeout.deadline.Sub(now); dist < 2*respTimeout { 411 timeout.Reset(dist) 412 return 413 } 414 // Remove pending replies whose deadline is too far in the 415 // future. These can occur if the system clock jumped 416 // backwards after the deadline was assigned. 417 nextTimeout.errc <- errClockWarp 418 plist.Remove(el) 419 } 420 nextTimeout = nil 421 timeout.Stop() 422 } 423 424 for { 425 resetTimeout() 426 427 select { 428 case <-t.closing: 429 for el := plist.Front(); el != nil; el = el.Next() { 430 el.Value.(*pending).errc <- errClosed 431 } 432 return 433 434 case p := <-t.addpending: 435 p.deadline = time.Now().Add(respTimeout) 436 plist.PushBack(p) 437 438 case r := <-t.gotreply: 439 var matched bool 440 for el := plist.Front(); el != nil; el = el.Next() { 441 p := el.Value.(*pending) 442 if p.from == r.from && p.ptype == r.ptype { 443 matched = true 444 // Remove the matcher if its callback indicates 445 // that all replies have been received. This is 446 // required for packet types that expect multiple 447 // reply packets. 448 if p.callback(r.data) { 449 p.errc <- nil 450 plist.Remove(el) 451 } 452 // Reset the continuous timeout counter (time drift detection) 453 contTimeouts = 0 454 } 455 } 456 r.matched <- matched 457 458 case now := <-timeout.C: 459 nextTimeout = nil 460 461 // Notify and remove callbacks whose deadline is in the past. 462 for el := plist.Front(); el != nil; el = el.Next() { 463 p := el.Value.(*pending) 464 if now.After(p.deadline) || now.Equal(p.deadline) { 465 p.errc <- errTimeout 466 plist.Remove(el) 467 contTimeouts++ 468 } 469 } 470 // If we've accumulated too many timeouts, do an NTP time sync check 471 if contTimeouts > ntpFailureThreshold { 472 if time.Since(ntpWarnTime) >= ntpWarningCooldown { 473 ntpWarnTime = time.Now() 474 go checkClockDrift() 475 } 476 contTimeouts = 0 477 } 478 } 479 } 480 } 481 482 const ( 483 macSize = 256 / 8 484 sigSize = 520 / 8 485 headSize = macSize + sigSize // space of packet frame data 486 ) 487 488 var ( 489 headSpace = make([]byte, headSize) 490 491 // Neighbors replies are sent across multiple packets to 492 // stay below the 1280 byte limit. We compute the maximum number 493 // of entries by stuffing a packet until it grows too large. 494 maxNeighbors int 495 ) 496 497 func init() { 498 p := neighbors{Expiration: ^uint64(0)} 499 maxSizeNode := rpcNode{IP: make(net.IP, 16), UDP: ^uint16(0), TCP: ^uint16(0)} 500 for n := 0; ; n++ { 501 p.Nodes = append(p.Nodes, maxSizeNode) 502 size, _, err := rlp.EncodeToReader(p) 503 if err != nil { 504 // If this ever happens, it will be caught by the unit tests. 505 panic("cannot encode: " + err.Error()) 506 } 507 if headSize+size+1 >= 1280 { 508 maxNeighbors = n 509 break 510 } 511 } 512 } 513 514 func (t *udp) send(toaddr *net.UDPAddr, ptype byte, req interface{}) error { 515 packet, err := encodePacket(t.priv, ptype, req) 516 if err != nil { 517 return err 518 } 519 if logger.MlogEnabled() { 520 switch ptype { 521 // @sorpass: again, performance penalty? 522 case pingPacket: 523 mlogPingSendTo.AssignDetails( 524 toaddr.String(), 525 len(packet), 526 ).Send(mlogDiscover) 527 case pongPacket: 528 mlogPongSendTo.AssignDetails( 529 toaddr.String(), 530 len(packet), 531 ).Send(mlogDiscover) 532 case findnodePacket: 533 mlogFindNodeSendTo.AssignDetails( 534 toaddr.String(), 535 len(packet), 536 ).Send(mlogDiscover) 537 case neighborsPacket: 538 mlogNeighborsSendTo.AssignDetails( 539 toaddr.String(), 540 len(packet), 541 ).Send(mlogDiscover) 542 } 543 } 544 if glog.V(logger.Detail) { 545 glog.Infof(">>> %v %T\n", toaddr, req) 546 } 547 548 if _, err = t.conn.WriteToUDP(packet, toaddr); err != nil { 549 glog.V(logger.Detail).Infoln("UDP send failed:", err) 550 } 551 return err 552 } 553 554 func encodePacket(priv *ecdsa.PrivateKey, ptype byte, req interface{}) ([]byte, error) { 555 b := new(bytes.Buffer) 556 b.Write(headSpace) 557 b.WriteByte(ptype) 558 if err := rlp.Encode(b, req); err != nil { 559 glog.V(logger.Error).Infoln("error encoding packet:", err) 560 return nil, err 561 } 562 packet := b.Bytes() 563 sig, err := crypto.Sign(crypto.Keccak256(packet[headSize:]), priv) 564 if err != nil { 565 glog.V(logger.Error).Infoln("could not sign packet:", err) 566 return nil, err 567 } 568 copy(packet[macSize:], sig) 569 // add the hash to the front. Note: this doesn't protect the 570 // packet in any way. Our public key will be part of this hash in 571 // The future. 572 copy(packet, crypto.Keccak256(packet[macSize:])) 573 return packet, nil 574 } 575 576 func isTemporaryError(err error) bool { 577 tempErr, ok := err.(interface { 578 Temporary() bool 579 }) 580 return ok && tempErr.Temporary() || isPacketTooBig(err) 581 } 582 583 // readLoop runs in its own goroutine. it handles incoming UDP packets. 584 func (t *udp) readLoop() { 585 defer t.conn.Close() 586 // Discovery packets are defined to be no larger than 1280 bytes. 587 // Packets larger than this size will be cut at the end and treated 588 // as invalid because their hash won't match. 589 buf := make([]byte, 1280) 590 for { 591 nbytes, from, err := t.conn.ReadFromUDP(buf) 592 if isTemporaryError(err) { 593 // Ignore temporary read errors. 594 glog.V(logger.Debug).Infof("Temporary read error: %v", err) 595 continue 596 } else if err != nil { 597 // Shut down the loop for permament errors. 598 glog.V(logger.Debug).Infof("Read error: %v", err) 599 return 600 } 601 t.handlePacket(from, buf[:nbytes]) 602 } 603 } 604 605 func (t *udp) handlePacket(from *net.UDPAddr, buf []byte) error { 606 packet, fromID, hash, err := decodePacket(buf) 607 if err != nil { 608 glog.V(logger.Debug).Infof("Bad packet from %v: %v\n", from, err) 609 return err 610 } 611 status := "ok" 612 if err = packet.handle(t, from, fromID, hash); err != nil { 613 status = err.Error() 614 } 615 if logger.MlogEnabled() { 616 // Use fmt Type interpolator to decide kind of request received, 617 // since packet is an interface with 1 method: handle. 618 switch p := fmt.Sprintf("%T", packet); p { 619 case "*discover.ping": 620 mlogPingHandleFrom.AssignDetails( 621 from.String(), 622 fromID.String(), 623 len(buf), 624 ).Send(mlogDiscover) 625 case "*discover.pong": 626 mlogPongHandleFrom.AssignDetails( 627 from.String(), 628 fromID.String(), 629 len(buf), 630 ).Send(mlogDiscover) 631 case "*discover.findnode": 632 mlogFindNodeHandleFrom.AssignDetails( 633 from.String(), 634 fromID.String(), 635 len(buf), 636 ).Send(mlogDiscover) 637 case "*discover.neighbors": 638 mlogNeighborsHandleFrom.AssignDetails( 639 from.String(), 640 fromID.String(), 641 len(buf), 642 ).Send(mlogDiscover) 643 } 644 } 645 if glog.V(logger.Detail) { 646 glog.Infof("<<< %v %T: %s\n", from, packet, status) 647 } 648 return err 649 } 650 651 func decodePacket(buf []byte) (packet, NodeID, []byte, error) { 652 if len(buf) < headSize+1 { 653 return nil, NodeID{}, nil, errPacketTooSmall 654 } 655 hash, sig, sigdata := buf[:macSize], buf[macSize:headSize], buf[headSize:] 656 shouldhash := crypto.Keccak256(buf[macSize:]) 657 if !bytes.Equal(hash, shouldhash) { 658 return nil, NodeID{}, nil, errBadHash 659 } 660 fromID, err := recoverNodeID(crypto.Keccak256(buf[headSize:]), sig) 661 if err != nil { 662 return nil, NodeID{}, hash, err 663 } 664 var req packet 665 switch ptype := sigdata[0]; ptype { 666 case pingPacket: 667 req = new(ping) 668 case pongPacket: 669 req = new(pong) 670 case findnodePacket: 671 req = new(findnode) 672 case neighborsPacket: 673 req = new(neighbors) 674 default: 675 return nil, fromID, hash, fmt.Errorf("unknown type: %d", ptype) 676 } 677 s := rlp.NewStream(bytes.NewReader(sigdata[1:]), 0) 678 err = s.Decode(req) 679 return req, fromID, hash, err 680 } 681 682 func (req *ping) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 683 if expired(req.Expiration) { 684 return errExpired 685 } 686 t.send(from, pongPacket, pong{ 687 To: makeEndpoint(from, req.From.TCP), 688 ReplyTok: mac, 689 Expiration: uint64(time.Now().Add(expiration).Unix()), 690 }) 691 if !t.handleReply(fromID, pingPacket, req) { 692 // Note: we're ignoring the provided IP address right now 693 go t.bond(true, fromID, from, req.From.TCP) 694 } 695 return nil 696 } 697 698 func (req *pong) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 699 if expired(req.Expiration) { 700 return errExpired 701 } 702 if !t.handleReply(fromID, pongPacket, req) { 703 return errUnsolicitedReply 704 } 705 return nil 706 } 707 708 func (req *findnode) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 709 if expired(req.Expiration) { 710 return errExpired 711 } 712 if t.db.node(fromID) == nil { 713 // No bond exists, we don't process the packet. This prevents 714 // an attack vector where the discovery protocol could be used 715 // to amplify traffic in a DDOS attack. A malicious actor 716 // would send a findnode request with the IP address and UDP 717 // port of the target as the source address. The recipient of 718 // the findnode packet would then send a neighbors packet 719 // (which is a much bigger packet than findnode) to the victim. 720 return errUnknownNode 721 } 722 closest := t.closest(req.Target).Slice() 723 724 p := neighbors{Expiration: uint64(time.Now().Add(expiration).Unix())} 725 726 // Send neighbors in chunks with at most maxNeighbors per packet 727 // to stay below the 1280 byte limit. 728 for i, n := range closest { 729 p.Nodes = append(p.Nodes, nodeToRPC(n)) 730 if len(p.Nodes) == maxNeighbors || i == len(closest)-1 { 731 t.send(from, neighborsPacket, p) 732 p.Nodes = p.Nodes[:0] 733 } 734 } 735 return nil 736 } 737 738 func (req *neighbors) handle(t *udp, from *net.UDPAddr, fromID NodeID, mac []byte) error { 739 if expired(req.Expiration) { 740 return errExpired 741 } 742 if !t.handleReply(fromID, neighborsPacket, req) { 743 return errUnsolicitedReply 744 } 745 return nil 746 } 747 748 func expired(ts uint64) bool { 749 return time.Unix(int64(ts), 0).Before(time.Now()) 750 } 751 752 func isReserved(ip net.IP) bool { 753 reserved := [][2]net.IP{ 754 Ipv4ReservedRangeThis, 755 Ipv4ReservedRangePrivateNetwork, 756 ipv4ReservedRangeProviderSubscriber, 757 Ipv4ReservedRangeLoopback, 758 ipv4ReservedRangeLinkLocal, 759 ipv4ReservedRangeLocalPrivate1, 760 ipv4ReservedRangeSpecialPurpose, 761 ipv4ReservedRangeTestNet1, 762 ipv4ReservedRange6to4, 763 Ipv4ReservedRangeLocalPrivate2, 764 ipv4ReservedRangeSubnets, 765 ipv4ReservedRangeTestNet2, 766 ipv4ReservedRangeTestNet3, 767 ipv4ReservedRangeMulticast, 768 ipv4ReservedRangeFuture, 769 ipv4ReservedRangeLimitedBroadcast, 770 ipv6ReservedRangeUnspecified, 771 Ipv6ReservedRangeLoopback, 772 ipv6ReservedRangeDocumentation, 773 ipv6ReservedRange6to4, 774 ipv6ReservedRangeUniqueLocal, 775 ipv6ReservedRangeLinkLocal, 776 ipv6ReservedRangeMulticast, 777 } 778 for _, r := range reserved { 779 isReserved, err := IpBetween(r[0], r[1], ip) 780 if err != nil { 781 glog.V(logger.Debug).Infof("error checking if ip reserved: %v", err) 782 return true 783 } 784 if isReserved { 785 return true 786 } 787 } 788 return false 789 } 790 791 // IpBetween determines if a given ip is between two others (inclusive) 792 // > https://stackoverflow.com/questions/19882961/go-golang-check-ip-address-in-range 793 func IpBetween(from net.IP, to net.IP, test net.IP) (bool, error) { 794 if from == nil || to == nil || test == nil { 795 return false, errInvalidIp 796 } 797 798 from16 := from.To16() 799 to16 := to.To16() 800 test16 := test.To16() 801 if from16 == nil || to16 == nil || test16 == nil { 802 return false, errors.New("ip did not convert to a 16 byte") 803 } 804 805 if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 { 806 return true, nil 807 } 808 return false, nil 809 }