github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/nat/natpmp.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:44</date> 10 //</624342658780762112> 11 12 13 package nat 14 15 import ( 16 "fmt" 17 "net" 18 "strings" 19 "time" 20 21 "github.com/jackpal/go-nat-pmp" 22 ) 23 24 //natpmpclient适应nat-pmp协议实现,因此它符合 25 //公共接口。 26 type pmp struct { 27 gw net.IP 28 c *natpmp.Client 29 } 30 31 func (n *pmp) String() string { 32 return fmt.Sprintf("NAT-PMP(%v)", n.gw) 33 } 34 35 func (n *pmp) ExternalIP() (net.IP, error) { 36 response, err := n.c.GetExternalAddress() 37 if err != nil { 38 return nil, err 39 } 40 return response.ExternalIPAddress[:], nil 41 } 42 43 func (n *pmp) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error { 44 if lifetime <= 0 { 45 return fmt.Errorf("lifetime must not be <= 0") 46 } 47 //注意,端口参数的顺序在 48 //addmapping和客户端的addportmapping。 49 _, err := n.c.AddPortMapping(strings.ToLower(protocol), intport, extport, int(lifetime/time.Second)) 50 return err 51 } 52 53 func (n *pmp) DeleteMapping(protocol string, extport, intport int) (err error) { 54 //若要销毁映射,请发送一个内部端口为的添加端口。 55 //要销毁的内部端口、零和A的外部端口 56 //时间为零。 57 _, err = n.c.AddPortMapping(strings.ToLower(protocol), intport, 0, 0) 58 return err 59 } 60 61 func discoverPMP() Interface { 62 //在所有可能的网关上运行外部地址查找 63 gws := potentialGateways() 64 found := make(chan *pmp, len(gws)) 65 for i := range gws { 66 gw := gws[i] 67 go func() { 68 c := natpmp.NewClient(gw) 69 if _, err := c.GetExternalAddress(); err != nil { 70 found <- nil 71 } else { 72 found <- &pmp{gw, c} 73 } 74 }() 75 } 76 //返回第一个响应的。 77 //发现需要很快,所以我们不再关心 78 //在非常短的超时之后的任何响应。 79 timeout := time.NewTimer(1 * time.Second) 80 defer timeout.Stop() 81 for range gws { 82 select { 83 case c := <-found: 84 if c != nil { 85 return c 86 } 87 case <-timeout.C: 88 return nil 89 } 90 } 91 return nil 92 } 93 94 var ( 95 //局域网IP范围 96 _, lan10, _ = net.ParseCIDR("10.0.0.0/8") 97 _, lan176, _ = net.ParseCIDR("172.16.0.0/12") 98 _, lan192, _ = net.ParseCIDR("192.168.0.0/16") 99 ) 100 101 //托多:改进这个。我们目前假设(在大多数网络上) 102 //路由器是本地局域网范围内的X.X.X.1。 103 func potentialGateways() (gws []net.IP) { 104 ifaces, err := net.Interfaces() 105 if err != nil { 106 return nil 107 } 108 for _, iface := range ifaces { 109 ifaddrs, err := iface.Addrs() 110 if err != nil { 111 return gws 112 } 113 for _, addr := range ifaddrs { 114 if x, ok := addr.(*net.IPNet); ok { 115 if lan10.Contains(x.IP) || lan176.Contains(x.IP) || lan192.Contains(x.IP) { 116 ip := x.IP.Mask(x.Mask).To4() 117 if ip != nil { 118 ip[3] = ip[3] | 0x01 119 gws = append(gws, ip) 120 } 121 } 122 } 123 } 124 } 125 return gws 126 } 127