github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/nat/natpmp.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package nat 26 27 import ( 28 "fmt" 29 "net" 30 "strings" 31 "time" 32 33 "github.com/jackpal/go-nat-pmp" 34 ) 35 36 //natpmpclient适应nat-pmp协议实现,因此它符合 37 //公共接口。 38 type pmp struct { 39 gw net.IP 40 c *natpmp.Client 41 } 42 43 func (n *pmp) String() string { 44 return fmt.Sprintf("NAT-PMP(%v)", n.gw) 45 } 46 47 func (n *pmp) ExternalIP() (net.IP, error) { 48 response, err := n.c.GetExternalAddress() 49 if err != nil { 50 return nil, err 51 } 52 return response.ExternalIPAddress[:], nil 53 } 54 55 func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error { 56 if lifetime <= 0 { 57 return fmt.Errorf("lifetime must not be <= 0") 58 } 59 //注意,端口参数的顺序在 60 //addmapping和客户端的addportmapping。 61 _, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second)) 62 return err 63 } 64 65 func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) { 66 //若要销毁映射,请发送一个内部端口为的添加端口。 67 //要销毁的内部端口、零和A的外部端口 68 //时间为零。 69 _, err = n.c.AddPortMapping(strings.ToLower(protocol), intport, 0, 0) 70 return err 71 } 72 73 func discoverPMP() Interface { 74 //在所有可能的网关上运行外部地址查找 75 gws := potentialGateways() 76 found := make(chan *pmp, len(gws)) 77 for i := range gws { 78 gw := gws[i] 79 go func() { 80 c := natpmp.NewClient(gw) 81 if _, err := c.GetExternalAddress(); err != nil { 82 found <- nil 83 } else { 84 found <- &pmp{gw, c} 85 } 86 }() 87 } 88 //返回第一个响应的。 89 //发现需要很快,所以我们不再关心 90 //在非常短的超时之后的任何响应。 91 timeout := time.NewTimer(1 * time.Second) 92 defer timeout.Stop() 93 for range gws { 94 select { 95 case c := <-found: 96 if c != nil { 97 return c 98 } 99 case <-timeout.C: 100 return nil 101 } 102 } 103 return nil 104 } 105 106 var ( 107 //局域网IP范围 108 _, lan10, _ = net.ParseCIDR("10.0.0.0/8") 109 _, lan176, _ = net.ParseCIDR("172.16.0.0/12") 110 _, lan192, _ = net.ParseCIDR("192.168.0.0/16") 111 ) 112 113 //托多:改进这个。我们目前假设(在大多数网络上) 114 //路由器是本地局域网范围内的X.X.X.1。 115 func potentialGateways() (gws []net.IP) { 116 ifaces, err := net.Interfaces() 117 if err != nil { 118 return nil 119 } 120 for _, iface := range ifaces { 121 ifaddrs, err := iface.Addrs() 122 if err != nil { 123 return gws 124 } 125 for _, addr := range ifaddrs { 126 if x, ok := addr.(*net.IPNet); ok { 127 if lan10.Contains(x.IP) || lan176.Contains(x.IP) || lan192.Contains(x.IP) { 128 ip := x.IP.Mask(x.Mask).To4() 129 if ip != nil { 130 ip[3] = ip[3] | 0x01 131 gws = append(gws, ip) 132 } 133 } 134 } 135 } 136 } 137 return gws 138 }