github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/p2p/nat/natupnp.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package nat 18 19 import ( 20 "errors" 21 "fmt" 22 "net" 23 "strings" 24 "time" 25 26 "github.com/huin/goupnp" 27 "github.com/huin/goupnp/dcps/internetgateway1" 28 "github.com/huin/goupnp/dcps/internetgateway2" 29 ) 30 31 const soapRequestTimeout = 3 * time.Second 32 33 type upnp struct { 34 dev *goupnp.RootDevice 35 service string 36 client upnpClient 37 } 38 39 type upnpClient interface { 40 GetExternalIPAddress() (string, error) 41 //GetLocalIP() (string, error) 42 AddPortMapping(string, uint16, string, uint16, string, bool, string, uint32) error 43 DeletePortMapping(string, uint16, string) error 44 GetNATRSIPStatus() (sip bool, nat bool, err error) 45 } 46 47 // GetLocalIP returns the non loopback local IP of the host 48 func (n *upnp)GetLocalIP()( string , error) { 49 addrs, err := net.InterfaceAddrs() 50 if err != nil { 51 return "", nil 52 } 53 for _, address := range addrs { 54 // check the address type and if it is not a loopback the display it 55 if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 56 if ipnet.IP.To4() != nil { 57 return ipnet.IP.String() , nil 58 } 59 } 60 } 61 return "", nil 62 } 63 64 func (n *upnp) ExternalIP() (addr net.IP, err error) { 65 ipString, err := n.client.GetExternalIPAddress() //getting from ipsharing public ip , nat upnp service IGDv2-ip1 66 67 //ipString, err := n.client.GetLocalIP() 68 if err != nil { 69 return nil, err 70 } 71 ip := net.ParseIP(ipString) //ip data type is ipv4 and ipv6 mapped address, so integrated to 16 byte long format 72 // 0 ~ 255.255. 125.131.89.105 : ipv6 used , ipv4 inserted ipv6 long format because of supporting ipv6 integration 73 if ip == nil { 74 return nil, errors.New("bad IP in response") 75 } 76 return ip, nil 77 } 78 79 func (n *upnp) AddMapping(protocol string, extport, intport int, desc string, lifetime time.Duration) error { 80 ip, err := n.internalAddress() 81 if err != nil { 82 return nil 83 } 84 protocol = strings.ToUpper(protocol) 85 lifetimeS := uint32(lifetime / time.Second) 86 n.DeleteMapping(protocol, extport, intport) 87 return n.client.AddPortMapping("", uint16(extport), protocol, uint16(intport), ip.String(), true, desc, lifetimeS) 88 } 89 90 func (n *upnp) internalAddress() (net.IP, error) { 91 devaddr, err := net.ResolveUDPAddr("udp4", n.dev.URLBase.Host) 92 if err != nil { 93 return nil, err 94 } 95 ifaces, err := net.Interfaces() 96 if err != nil { 97 return nil, err 98 } 99 for _, iface := range ifaces { 100 addrs, err := iface.Addrs() 101 if err != nil { 102 return nil, err 103 } 104 for _, addr := range addrs { 105 switch x := addr.(type) { 106 case *net.IPNet: 107 if x.Contains(devaddr.IP) { 108 return x.IP, nil 109 } 110 } 111 } 112 } 113 return nil, fmt.Errorf("could not find local address in same net as %v", devaddr) 114 } 115 116 func (n *upnp) DeleteMapping(protocol string, extport, intport int) error { 117 return n.client.DeletePortMapping("", uint16(extport), strings.ToUpper(protocol)) 118 } 119 120 func (n *upnp) String() string { 121 //log.Info("==========UPnP String() runned ! ============") 122 //fmt.Errorf("==========UPnP String() runned ! ============: n= %v, n=service%v", n, n.service) 123 return "UPNP " + n.service 124 } 125 126 // discoverUPnP searches for Internet Gateway Devices 127 // and returns the first one it can find on the local network. 128 func discoverUPnP() Interface { 129 found := make(chan *upnp, 2) 130 // IGDv1 131 go discover(found, internetgateway1.URN_WANConnectionDevice_1, func(dev *goupnp.RootDevice, sc goupnp.ServiceClient) *upnp { 132 switch sc.Service.ServiceType { 133 case internetgateway1.URN_WANIPConnection_1: 134 return &upnp{dev, "IGDv1-IP1", &internetgateway1.WANIPConnection1{ServiceClient: sc}} 135 case internetgateway1.URN_WANPPPConnection_1: 136 return &upnp{dev, "IGDv1-PPP1", &internetgateway1.WANPPPConnection1{ServiceClient: sc}} 137 } 138 return nil 139 }) 140 // IGDv2 141 go discover(found, internetgateway2.URN_WANConnectionDevice_2, func(dev *goupnp.RootDevice, sc goupnp.ServiceClient) *upnp { 142 switch sc.Service.ServiceType { 143 case internetgateway2.URN_WANIPConnection_1: 144 return &upnp{dev, "IGDv2-IP1", &internetgateway2.WANIPConnection1{ServiceClient: sc}} 145 case internetgateway2.URN_WANIPConnection_2: 146 return &upnp{dev, "IGDv2-IP2", &internetgateway2.WANIPConnection2{ServiceClient: sc}} 147 case internetgateway2.URN_WANPPPConnection_1: 148 return &upnp{dev, "IGDv2-PPP1", &internetgateway2.WANPPPConnection1{ServiceClient: sc}} 149 } 150 return nil 151 }) 152 for i := 0; i < cap(found); i++ { 153 if c := <-found; c != nil { 154 return c 155 } 156 } 157 return nil 158 } 159 160 // finds devices matching the given target and calls matcher for all 161 // advertised services of each device. The first non-nil service found 162 // is sent into out. If no service matched, nil is sent. 163 func discover(out chan<- *upnp, target string, matcher func(*goupnp.RootDevice, goupnp.ServiceClient) *upnp) { 164 devs, err := goupnp.DiscoverDevices(target) 165 if err != nil { 166 out <- nil 167 return 168 } 169 found := false 170 for i := 0; i < len(devs) && !found; i++ { 171 if devs[i].Root == nil { 172 continue 173 } 174 devs[i].Root.Device.VisitServices(func(service *goupnp.Service) { 175 if found { 176 return 177 } 178 // check for a matching IGD service 179 sc := goupnp.ServiceClient{ 180 SOAPClient: service.NewSOAPClient(), 181 RootDevice: devs[i].Root, 182 Location: devs[i].Location, 183 Service: service, 184 } 185 sc.SOAPClient.HTTPClient.Timeout = soapRequestTimeout 186 upnp := matcher(devs[i].Root, sc) 187 if upnp == nil { 188 return 189 } 190 // check whether port mapping is enabled 191 if _, nat, err := upnp.client.GetNATRSIPStatus(); err != nil || !nat { 192 return 193 } 194 out <- upnp 195 found = true 196 }) 197 } 198 if !found { 199 out <- nil 200 } 201 }