github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/nat/nat.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  //</624342658696876032>
    11  
    12  
    13  //包NAT提供对公共网络端口映射协议的访问。
    14  package nat
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"net"
    20  	"strings"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/ethereum/go-ethereum/log"
    25  	"github.com/jackpal/go-nat-pmp"
    26  )
    27  
    28  //一个nat.interface的实现可以将本地端口映射到端口
    29  //可从Internet访问。
    30  type Interface interface {
    31  //这些方法管理本地端口之间的映射
    32  //机器到可以从Internet连接到的端口。
    33  //
    34  //协议是“udp”或“tcp”。某些实现允许设置
    35  //映射的显示名称。映射可以通过
    36  //网关的生命周期结束时。
    37  	AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error
    38  	DeleteMapping(protocol string, extport, intport int) error
    39  
    40  //此方法应返回外部(面向Internet)
    41  //网关设备的地址。
    42  	ExternalIP() (net.IP, error)
    43  
    44  //应返回方法的名称。这用于日志记录。
    45  	String() string
    46  }
    47  
    48  //解析解析一个NAT接口描述。
    49  //当前接受以下格式。
    50  //请注意,机制名称不区分大小写。
    51  //
    52  //“”或“无”返回零
    53  //“extip:77.12.33.4”将假定在给定的IP上可以访问本地计算机。
    54  //“任意”使用第一个自动检测机制
    55  //“UPNP”使用通用即插即用协议
    56  //“pmp”使用具有自动检测到的网关地址的nat-pmp
    57  //“pmp:192.168.0.1”使用具有给定网关地址的nat-pmp
    58  func Parse(spec string) (Interface, error) {
    59  	var (
    60  		parts = strings.SplitN(spec, ":", 2)
    61  		mech  = strings.ToLower(parts[0])
    62  		ip    net.IP
    63  	)
    64  	if len(parts) > 1 {
    65  		ip = net.ParseIP(parts[1])
    66  		if ip == nil {
    67  			return nil, errors.New("invalid IP address")
    68  		}
    69  	}
    70  	switch mech {
    71  	case "", "none", "off":
    72  		return nil, nil
    73  	case "any", "auto", "on":
    74  		return Any(), nil
    75  	case "extip", "ip":
    76  		if ip == nil {
    77  			return nil, errors.New("missing IP address")
    78  		}
    79  		return ExtIP(ip), nil
    80  	case "upnp":
    81  		return UPnP(), nil
    82  	case "pmp", "natpmp", "nat-pmp":
    83  		return PMP(ip), nil
    84  	default:
    85  		return nil, fmt.Errorf("unknown mechanism %q", parts[0])
    86  	}
    87  }
    88  
    89  const (
    90  	mapTimeout        = 20 * time.Minute
    91  	mapUpdateInterval = 15 * time.Minute
    92  )
    93  
    94  //map在m上添加了一个端口映射,并在c关闭之前保持它的活动状态。
    95  //此函数通常在自己的goroutine中调用。
    96  func Map(m Interface, c chan struct{}, protocol string, extport, intport int, name string) {
    97  	log := log.New("proto", protocol, "extport", extport, "intport", intport, "interface", m)
    98  	refresh := time.NewTimer(mapUpdateInterval)
    99  	defer func() {
   100  		refresh.Stop()
   101  		log.Debug("Deleting port mapping")
   102  		m.DeleteMapping(protocol, extport, intport)
   103  	}()
   104  	if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
   105  		log.Debug("Couldn't add port mapping", "err", err)
   106  	} else {
   107  		log.Info("Mapped network port")
   108  	}
   109  	for {
   110  		select {
   111  		case _, ok := <-c:
   112  			if !ok {
   113  				return
   114  			}
   115  		case <-refresh.C:
   116  			log.Trace("Refreshing port mapping")
   117  			if err := m.AddMapping(protocol, extport, intport, name, mapTimeout); err != nil {
   118  				log.Debug("Couldn't add port mapping", "err", err)
   119  			}
   120  			refresh.Reset(mapUpdateInterval)
   121  		}
   122  	}
   123  }
   124  
   125  //extip假定在给定的
   126  //外部IP地址,以及手动映射所需的任何端口。
   127  //映射操作不会返回错误,但实际上不会执行任何操作。
   128  func ExtIP(ip net.IP) Interface {
   129  	if ip == nil {
   130  		panic("IP must not be nil")
   131  	}
   132  	return extIP(ip)
   133  }
   134  
   135  type extIP net.IP
   136  
   137  func (n extIP) ExternalIP() (net.IP, error) { return net.IP(n), nil }
   138  func (n extIP) String() string              { return fmt.Sprintf("ExtIP(%v)", net.IP(n)) }
   139  
   140  //这些什么都不做。
   141  func (extIP) AddMapping(string, int, int, string, time.Duration) error { return nil }
   142  func (extIP) DeleteMapping(string, int, int) error                     { return nil }
   143  
   144  //any返回一个端口映射器,该映射器尝试发现任何支持的
   145  //本地网络上的机制。
   146  func Any() Interface {
   147  //TODO:尝试发现本地计算机是否具有
   148  //Internet类地址。在这种情况下返回extip。
   149  	return startautodisc("UPnP or NAT-PMP", func() Interface {
   150  		found := make(chan Interface, 2)
   151  		go func() { found <- discoverUPnP() }()
   152  		go func() { found <- discoverPMP() }()
   153  		for i := 0; i < cap(found); i++ {
   154  			if c := <-found; c != nil {
   155  				return c
   156  			}
   157  		}
   158  		return nil
   159  	})
   160  }
   161  
   162  //UPNP返回使用UPNP的端口映射器。它将试图
   163  //使用UDP广播发现路由器的地址。
   164  func UPnP() Interface {
   165  	return startautodisc("UPnP", discoverUPnP)
   166  }
   167  
   168  //pmp返回使用nat-pmp的端口映射器。提供的网关
   169  //地址应该是路由器的IP。如果给定的网关
   170  //地址为零,PMP将尝试自动发现路由器。
   171  func PMP(gateway net.IP) Interface {
   172  	if gateway != nil {
   173  		return &pmp{gw: gateway, c: natpmp.NewClient(gateway)}
   174  	}
   175  	return startautodisc("NAT-PMP", discoverPMP)
   176  }
   177  
   178  //自动发现表示仍在
   179  //自动发现。调用此类型上的接口方法将
   180  //等待发现完成,然后在
   181  //发现了机制。
   182  //
   183  //这种类型很有用,因为发现可能需要一段时间,但是我们
   184  //要立即从upnp、pmp和auto返回接口值。
   185  type autodisc struct {
   186  what string //正在自动发现的接口类型
   187  	once sync.Once
   188  	doit func() Interface
   189  
   190  	mu    sync.Mutex
   191  	found Interface
   192  }
   193  
   194  func startautodisc(what string, doit func() Interface) Interface {
   195  //TODO:监视网络配置,并在其更改时重新运行DOIT。
   196  	return &autodisc{what: what, doit: doit}
   197  }
   198  
   199  func (n *autodisc) AddMapping(protocol string, extport, intport int, name string, lifetime time.Duration) error {
   200  	if err := n.wait(); err != nil {
   201  		return err
   202  	}
   203  	return n.found.AddMapping(protocol, extport, intport, name, lifetime)
   204  }
   205  
   206  func (n *autodisc) DeleteMapping(protocol string, extport, intport int) error {
   207  	if err := n.wait(); err != nil {
   208  		return err
   209  	}
   210  	return n.found.DeleteMapping(protocol, extport, intport)
   211  }
   212  
   213  func (n *autodisc) ExternalIP() (net.IP, error) {
   214  	if err := n.wait(); err != nil {
   215  		return nil, err
   216  	}
   217  	return n.found.ExternalIP()
   218  }
   219  
   220  func (n *autodisc) String() string {
   221  	n.mu.Lock()
   222  	defer n.mu.Unlock()
   223  	if n.found == nil {
   224  		return n.what
   225  	} else {
   226  		return n.found.String()
   227  	}
   228  }
   229  
   230  //等待块,直到执行自动发现。
   231  func (n *autodisc) wait() error {
   232  	n.once.Do(func() {
   233  		n.mu.Lock()
   234  		n.found = n.doit()
   235  		n.mu.Unlock()
   236  	})
   237  	if n.found == nil {
   238  		return fmt.Errorf("no %s router discovered", n.what)
   239  	}
   240  	return nil
   241  }
   242