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  }