github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/nat/natupnp.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 "errors" 29 "fmt" 30 "net" 31 "strings" 32 "time" 33 34 "github.com/huin/goupnp" 35 "github.com/huin/goupnp/dcps/internetgateway1" 36 "github.com/huin/goupnp/dcps/internetgateway2" 37 ) 38 39 const soapRequestTimeout = 3 * time.Second 40 41 type upnp struct { 42 dev *goupnp.RootDevice 43 service string 44 client upnpClient 45 } 46 47 type upnpClient interface { 48 GetExternalIPAddress() (string, error) 49 AddPortMapping(string, uint16, string, uint16, string, bool, string, uint32) error 50 DeletePortMapping(string, uint16, string) error 51 GetNATRSIPStatus() (sip bool, nat bool, err error) 52 } 53 54 func (n *upnp) ExternalIP() (addr net.IP, err error) { 55 ipString, err := n.client.GetExternalIPAddress() 56 if err != nil { 57 return nil, err 58 } 59 ip := net.ParseIP(ipString) 60 if ip == nil { 61 return nil, errors.New("bad IP in response") 62 } 63 return ip, nil 64 } 65 66 func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, lifetime time.Duration) error { 67 ip, err := n.internalAddress() 68 if err != nil { 69 return nil 70 } 71 protocol = strings.ToUpper(protocol) 72 lifetimeS := uint32(lifetime / time.Second) 73 n.DeleteMapping(protocol, extport, intport) 74 return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) 75 } 76 77 func (n *upnp) internalAddress() (net.IP, error) { 78 devaddr, err := net.ResolveUDPAddr("udp4", n.dev.URLBase.Host) 79 if err != nil { 80 return nil, err 81 } 82 ifaces, err := net.Interfaces() 83 if err != nil { 84 return nil, err 85 } 86 for _, iface := range ifaces { 87 addrs, err := iface.Addrs() 88 if err != nil { 89 return nil, err 90 } 91 for _, addr := range addrs { 92 if x, ok := addr.(*net.IPNet); ok && x.Contains(devaddr.IP) { 93 return x.IP, nil 94 } 95 } 96 } 97 return nil, fmt.Errorf("could not find local address in same net as %v", devaddr) 98 } 99 100 func (n *upnp) DeleteMapping(protocol string, extport, intport int) error { 101 return n.client.DeletePortMapping("", uint16(extport), strings.ToUpper(protocol)) 102 } 103 104 func (n *upnp) String() string { 105 return "UPNP " + n.service 106 } 107 108 //Discoverupnp搜索Internet网关设备 109 //并返回在本地网络上找到的第一个。 110 func discoverUPnP() Interface { 111 found := make(chan *upnp, 2) 112 //IGDV1 113 go discover(found, internetgateway1.URN_WANConnectionDevice_1, func(dev *goupnp.RootDevice, sc goupnp.ServiceClient) *upnp { 114 switch sc.Service.ServiceType { 115 case internetgateway1.URN_WANIPConnection_1: 116 return &upnp{dev, "IGDv1-IP1", &internetgateway1.WANIPConnection1{ServiceClient: sc}} 117 case internetgateway1.URN_WANPPPConnection_1: 118 return &upnp{dev, "IGDv1-PPP1", &internetgateway1.WANPPPConnection1{ServiceClient: sc}} 119 } 120 return nil 121 }) 122 //IGDV2 123 go discover(found, internetgateway2.URN_WANConnectionDevice_2, func(dev *goupnp.RootDevice, sc goupnp.ServiceClient) *upnp { 124 switch sc.Service.ServiceType { 125 case internetgateway2.URN_WANIPConnection_1: 126 return &upnp{dev, "IGDv2-IP1", &internetgateway2.WANIPConnection1{ServiceClient: sc}} 127 case internetgateway2.URN_WANIPConnection_2: 128 return &upnp{dev, "IGDv2-IP2", &internetgateway2.WANIPConnection2{ServiceClient: sc}} 129 case internetgateway2.URN_WANPPPConnection_1: 130 return &upnp{dev, "IGDv2-PPP1", &internetgateway2.WANPPPConnection1{ServiceClient: sc}} 131 } 132 return nil 133 }) 134 for i := 0; i < cap(found); i++ { 135 if c := <-found; c != nil { 136 return c 137 } 138 } 139 return nil 140 } 141 142 //查找与给定目标匹配的设备并为所有设备调用Matcher 143 //每个设备的广告服务。找到第一个非零服务 144 //被送出去。如果没有匹配的服务,则发送nil。 145 func discover(out chan<- *upnp, target string, matcher func(*goupnp.RootDevice, goupnp.ServiceClient) *upnp) { 146 devs, err := goupnp.DiscoverDevices(target) 147 if err != nil { 148 out <- nil 149 return 150 } 151 found := false 152 for i := 0; i < len(devs) && !found; i++ { 153 if devs[i].Root == nil { 154 continue 155 } 156 devs[i].Root.Device.VisitServices(func(service *goupnp.Service) { 157 if found { 158 return 159 } 160 //检查匹配的IGD服务 161 sc := goupnp.ServiceClient{ 162 SOAPClient: service.NewSOAPClient(), 163 RootDevice: devs[i].Root, 164 Location: devs[i].Location, 165 Service: service, 166 } 167 sc.SOAPClient.HTTPClient.Timeout = soapRequestTimeout 168 upnp := matcher(devs[i].Root, sc) 169 if upnp == nil { 170 return 171 } 172 //检查是否启用端口映射 173 if _, nat, err := upnp.client.GetNATRSIPStatus(); err != nil || !nat { 174 return 175 } 176 out <- upnp 177 found = true 178 }) 179 } 180 if !found { 181 out <- nil 182 } 183 }