natpmp.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. package nat
  17. import (
  18. "fmt"
  19. "net"
  20. "strings"
  21. "time"
  22. "blockchain-go/common/gopool"
  23. natpmp "github.com/jackpal/go-nat-pmp"
  24. )
  25. // natPMPClient adapts the NAT-PMP protocol implementation so it conforms to
  26. // the common interface.
  27. type pmp struct {
  28. gw net.IP
  29. c *natpmp.Client
  30. }
  31. func (n *pmp) String() string {
  32. return fmt.Sprintf("NAT-PMP(%v)", n.gw)
  33. }
  34. func (n *pmp) ExternalIP() (net.IP, error) {
  35. response, err := n.c.GetExternalAddress()
  36. if err != nil {
  37. return nil, err
  38. }
  39. return response.ExternalIPAddress[:], nil
  40. }
  41. func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error {
  42. if lifetime <= 0 {
  43. return fmt.Errorf("lifetime must not be <= 0")
  44. }
  45. // Note order of port arguments is switched between our
  46. // AddMapping and the client's AddPortMapping.
  47. _, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second))
  48. return err
  49. }
  50. func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) {
  51. // To destroy a mapping, send an add-port with an internalPort of
  52. // the internal port to destroy, an external port of zero and a
  53. // time of zero.
  54. _, err = n.c.AddPortMapping(strings.ToLower(protocol), intport, 0, 0)
  55. return err
  56. }
  57. func discoverPMP() Interface {
  58. // run external address lookups on all potential gateways
  59. gws := potentialGateways()
  60. found := make(chan *pmp, len(gws))
  61. for i := range gws {
  62. gw := gws[i]
  63. gopool.Submit(func() {
  64. c := natpmp.NewClient(gw)
  65. if _, err := c.GetExternalAddress(); err != nil {
  66. found <- nil
  67. } else {
  68. found <- &pmp{gw, c}
  69. }
  70. })
  71. }
  72. // return the one that responds first.
  73. // discovery needs to be quick, so we stop caring about
  74. // any responses after a very short timeout.
  75. timeout := time.NewTimer(1 * time.Second)
  76. defer timeout.Stop()
  77. for range gws {
  78. select {
  79. case c := <-found:
  80. if c != nil {
  81. return c
  82. }
  83. case <-timeout.C:
  84. return nil
  85. }
  86. }
  87. return nil
  88. }
  89. var (
  90. // LAN IP ranges
  91. _, lan10, _ = net.ParseCIDR("10.0.0.0/8")
  92. _, lan176, _ = net.ParseCIDR("172.16.0.0/12")
  93. _, lan192, _ = net.ParseCIDR("192.168.0.0/16")
  94. )
  95. // TODO: improve this. We currently assume that (on most networks)
  96. // the router is X.X.X.1 in a local LAN range.
  97. func potentialGateways() (gws []net.IP) {
  98. ifaces, err := net.Interfaces()
  99. if err != nil {
  100. return nil
  101. }
  102. for _, iface := range ifaces {
  103. ifaddrs, err := iface.Addrs()
  104. if err != nil {
  105. return gws
  106. }
  107. for _, addr := range ifaddrs {
  108. if x, ok := addr.(*net.IPNet); ok {
  109. if lan10.Contains(x.IP) || lan176.Contains(x.IP) || lan192.Contains(x.IP) {
  110. ip := x.IP.Mask(x.Mask).To4()
  111. if ip != nil {
  112. ip[3] = ip[3] | 0x01
  113. gws = append(gws, ip)
  114. }
  115. }
  116. }
  117. }
  118. }
  119. return gws
  120. }