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