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  }