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