mirror of https://github.com/poanetwork/gecko.git
upnp
This commit is contained in:
parent
0d9a21b458
commit
aaa00b3488
2
go.mod
2
go.mod
|
@ -28,7 +28,7 @@ require (
|
|||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mr-tron/base58 v1.1.3
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d
|
||||
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
||||
github.com/pborman/uuid v1.2.0 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -165,6 +165,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
|
|
|
@ -68,11 +68,11 @@ func main() {
|
|||
log.Debug("assertions are enabled. This may slow down execution")
|
||||
}
|
||||
|
||||
mapper := nat.NewDefaultMapper(log, Config.Nat, nat.TCP, "gecko")
|
||||
defer mapper.UnmapAllPorts()
|
||||
router := nat.NewRouter(log, Config.Nat)
|
||||
defer router.UnmapAllPorts()
|
||||
|
||||
mapper.MapPort(Config.StakingIP.Port, Config.StakingIP.Port)
|
||||
mapper.MapPort(Config.HTTPPort, Config.HTTPPort)
|
||||
router.Map("TCP", Config.StakingIP.Port, Config.StakingIP.Port, "gecko")
|
||||
router.Map("TCP", Config.HTTPPort, Config.HTTPPort, "gecko http")
|
||||
|
||||
node := node.Node{}
|
||||
|
||||
|
|
|
@ -281,12 +281,12 @@ func init() {
|
|||
Config.DB = memdb.New()
|
||||
}
|
||||
|
||||
Config.Nat = nat.NewRouter()
|
||||
Config.Nat = nat.GetNATRouter()
|
||||
|
||||
var ip net.IP
|
||||
// If public IP is not specified, get it using shell command dig
|
||||
if *consensusIP == "" {
|
||||
ip, err = Config.Nat.IP()
|
||||
ip, err = Config.Nat.ExternalIP()
|
||||
if err != nil {
|
||||
ip = net.IPv4zero // Couldn't get my IP...set to 0.0.0.0
|
||||
}
|
||||
|
|
143
nat/mapper.go
143
nat/mapper.go
|
@ -1,143 +0,0 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package nat
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/gecko/utils/logging"
|
||||
"github.com/ava-labs/gecko/utils/wrappers"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMappingTimeout = 30 * time.Minute
|
||||
defaultMappingUpdateInterval = 3 * defaultMappingTimeout / 4
|
||||
)
|
||||
|
||||
// Mapper maps port
|
||||
type Mapper interface {
|
||||
MapPort(newInternalPort, newExternalPort uint16) error
|
||||
UnmapAllPorts() error
|
||||
}
|
||||
|
||||
type mapper struct {
|
||||
log logging.Logger
|
||||
router Router
|
||||
networkProtocol NetworkProtocol
|
||||
mappingNames string
|
||||
mappingTimeout time.Duration
|
||||
mappingUpdateInterval time.Duration
|
||||
|
||||
closer chan struct{}
|
||||
wg sync.WaitGroup
|
||||
errLock sync.Mutex
|
||||
errs wrappers.Errs
|
||||
}
|
||||
|
||||
// NewMapper returns a new mapper that can map ports on a router
|
||||
func NewMapper(
|
||||
log logging.Logger,
|
||||
router Router,
|
||||
networkProtocol NetworkProtocol,
|
||||
mappingNames string,
|
||||
mappingTimeout time.Duration,
|
||||
mappingUpdateInterval time.Duration,
|
||||
) Mapper {
|
||||
return &mapper{
|
||||
log: log,
|
||||
router: router,
|
||||
networkProtocol: networkProtocol,
|
||||
mappingNames: mappingNames,
|
||||
mappingTimeout: mappingTimeout,
|
||||
mappingUpdateInterval: mappingUpdateInterval,
|
||||
closer: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultMapper returns a new mapper that can map ports on a router with
|
||||
// default settings
|
||||
func NewDefaultMapper(
|
||||
log logging.Logger,
|
||||
router Router,
|
||||
networkProtocol NetworkProtocol,
|
||||
mappingNames string,
|
||||
) Mapper {
|
||||
return NewMapper(
|
||||
log,
|
||||
router,
|
||||
networkProtocol,
|
||||
mappingNames,
|
||||
defaultMappingTimeout, // uses the default value
|
||||
defaultMappingUpdateInterval, // uses the default value
|
||||
)
|
||||
}
|
||||
|
||||
// MapPort maps a local port to a port on the router until UnmapAllPorts is
|
||||
// called.
|
||||
func (m *mapper) MapPort(newInternalPort, newExternalPort uint16) error {
|
||||
m.wg.Add(1)
|
||||
go m.mapPort(newInternalPort, newExternalPort)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mapper) mapPort(newInternalPort, newExternalPort uint16) {
|
||||
// duration is set to 0 here so that the select case will execute
|
||||
// immediately
|
||||
updateTimer := time.NewTimer(0)
|
||||
defer func() {
|
||||
updateTimer.Stop()
|
||||
|
||||
m.errLock.Lock()
|
||||
m.errs.Add(m.router.UnmapPort(
|
||||
m.networkProtocol,
|
||||
newInternalPort,
|
||||
newExternalPort))
|
||||
m.errLock.Unlock()
|
||||
|
||||
m.log.Debug("Unmapped external port %d to internal port %d",
|
||||
newExternalPort,
|
||||
newInternalPort)
|
||||
|
||||
m.wg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-updateTimer.C:
|
||||
err := m.router.MapPort(
|
||||
m.networkProtocol,
|
||||
newInternalPort,
|
||||
newExternalPort,
|
||||
m.mappingNames,
|
||||
m.mappingTimeout)
|
||||
|
||||
if err != nil {
|
||||
m.errLock.Lock()
|
||||
m.errs.Add(err)
|
||||
m.errLock.Unlock()
|
||||
|
||||
m.log.Debug("Failed to add mapping from external port %d to internal port %d due to %s",
|
||||
newExternalPort,
|
||||
newInternalPort,
|
||||
err)
|
||||
} else {
|
||||
m.log.Debug("Mapped external port %d to internal port %d",
|
||||
newExternalPort,
|
||||
newInternalPort)
|
||||
}
|
||||
|
||||
// remap the port in m.mappingUpdateInterval
|
||||
updateTimer.Reset(m.mappingUpdateInterval)
|
||||
case _, _ = <-m.closer:
|
||||
return // only return when all ports are unmapped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mapper) UnmapAllPorts() error {
|
||||
close(m.closer)
|
||||
m.wg.Wait()
|
||||
return m.errs.Err
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package nat
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ava-labs/gecko/utils/logging"
|
||||
"github.com/ava-labs/gecko/utils/wrappers"
|
||||
)
|
||||
|
||||
const (
|
||||
mapTimeout = 30 * time.Minute
|
||||
mapUpdate = mapTimeout / 2
|
||||
)
|
||||
|
||||
type NATRouter interface {
|
||||
MapPort(protocol string, intport, extport uint16, desc string, duration time.Duration) error
|
||||
UnmapPort(protocol string, extport uint16) error
|
||||
ExternalIP() (net.IP, error)
|
||||
}
|
||||
|
||||
func GetNATRouter() NATRouter {
|
||||
//TODO other protocol
|
||||
return getUPnPRouter()
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
log logging.Logger
|
||||
r NATRouter
|
||||
closer chan struct{}
|
||||
wg sync.WaitGroup
|
||||
errLock sync.Mutex
|
||||
errs wrappers.Errs
|
||||
}
|
||||
|
||||
func NewRouter(log logging.Logger, r NATRouter) Router {
|
||||
return Router{
|
||||
log: log,
|
||||
r: r,
|
||||
closer: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *Router) Map(protocol string, intport, extport uint16, desc string) {
|
||||
dev.wg.Add(1)
|
||||
go dev.mapPort(protocol, intport, extport, desc)
|
||||
}
|
||||
|
||||
func (dev *Router) mapPort(protocol string, intport, extport uint16, desc string) {
|
||||
updater := time.NewTimer(mapUpdate)
|
||||
defer func() {
|
||||
updater.Stop()
|
||||
|
||||
dev.log.Info("Unmap protocol %s external port %d", protocol, extport)
|
||||
dev.errLock.Lock()
|
||||
dev.errs.Add(dev.r.UnmapPort(protocol, extport))
|
||||
dev.errLock.Unlock()
|
||||
|
||||
dev.wg.Done()
|
||||
}()
|
||||
|
||||
if err := dev.r.MapPort(protocol, intport, extport, desc, mapTimeout); err != nil {
|
||||
dev.log.Warn("Map port failed. Protocol %s Internal %d External %d. %s",
|
||||
protocol, intport, extport, err)
|
||||
dev.errLock.Lock()
|
||||
dev.errs.Add(err)
|
||||
dev.errLock.Unlock()
|
||||
} else {
|
||||
dev.log.Info("Mapped Protocol %s Internal %d External %d. %s", protocol,
|
||||
intport, extport)
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-updater.C:
|
||||
if err := dev.r.MapPort(protocol, intport, extport, desc, mapTimeout); err != nil {
|
||||
dev.log.Warn("Renew port mapping failed. Protocol %s Internal %d External %d. %s",
|
||||
protocol, intport, extport, err)
|
||||
} else {
|
||||
dev.log.Info("Renew port mapping Protocol %s Internal %d External %d. %s", protocol,
|
||||
intport, extport)
|
||||
}
|
||||
|
||||
updater.Reset(mapUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dev *Router) UnmapAllPorts() error {
|
||||
close(dev.closer)
|
||||
dev.wg.Wait()
|
||||
return dev.errs.Err
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package nat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoRouter = errors.New("no nat enabled router was discovered")
|
||||
)
|
||||
|
||||
type noRouter struct{}
|
||||
|
||||
func (noRouter) MapPort(_ NetworkProtocol, _, _ uint16, _ string, _ time.Duration) error {
|
||||
return errNoRouter
|
||||
}
|
||||
|
||||
func (noRouter) UnmapPort(_ NetworkProtocol, _, _ uint16) error {
|
||||
return errNoRouter
|
||||
}
|
||||
|
||||
func (noRouter) IP() (net.IP, error) {
|
||||
return nil, errNoRouter
|
||||
}
|
71
nat/pmp.go
71
nat/pmp.go
|
@ -1,71 +0,0 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package nat
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/jackpal/gateway"
|
||||
"github.com/jackpal/go-nat-pmp"
|
||||
)
|
||||
|
||||
var (
|
||||
pmpClientTimeout = 500 * time.Millisecond
|
||||
)
|
||||
|
||||
// natPMPClient adapts the NAT-PMP protocol implementation so it conforms to
|
||||
// the common interface.
|
||||
type pmpClient struct {
|
||||
client *natpmp.Client
|
||||
}
|
||||
|
||||
func (pmp *pmpClient) MapPort(
|
||||
networkProtocol NetworkProtocol,
|
||||
newInternalPort uint16,
|
||||
newExternalPort uint16,
|
||||
mappingName string,
|
||||
mappingDuration time.Duration) error {
|
||||
protocol := string(networkProtocol)
|
||||
internalPort := int(newInternalPort)
|
||||
externalPort := int(newExternalPort)
|
||||
// go-nat-pmp uses seconds to denote their lifetime
|
||||
lifetime := int(mappingDuration / time.Second)
|
||||
|
||||
_, err := pmp.client.AddPortMapping(protocol, internalPort, externalPort, lifetime)
|
||||
return err
|
||||
}
|
||||
|
||||
func (pmp *pmpClient) UnmapPort(
|
||||
networkProtocol NetworkProtocol,
|
||||
internalPort uint16,
|
||||
_ uint16) error {
|
||||
protocol := string(networkProtocol)
|
||||
internalPortInt := int(internalPort)
|
||||
|
||||
_, err := pmp.client.AddPortMapping(protocol, internalPortInt, 0, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
func (pmp *pmpClient) IP() (net.IP, error) {
|
||||
response, err := pmp.client.GetExternalAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response.ExternalIPAddress[:], nil
|
||||
}
|
||||
|
||||
func getPMPRouter() Router {
|
||||
gatewayIP, err := gateway.DiscoverGateway()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pmp := &pmpClient{natpmp.NewClientWithTimeout(gatewayIP, pmpClientTimeout)}
|
||||
if _, err := pmp.IP(); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return pmp
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
// Package nat performs network address translation and provides helpers for
|
||||
// routing ports.
|
||||
package nat
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NetworkProtocol is a protocol that will be used through a port
|
||||
type NetworkProtocol string
|
||||
|
||||
// Available protocol
|
||||
const (
|
||||
TCP NetworkProtocol = "TCP"
|
||||
UDP NetworkProtocol = "UDP"
|
||||
)
|
||||
|
||||
// Router provides a standard NAT router functions. Specifically, allowing the
|
||||
// fetching of public IPs and port forwarding to this computer.
|
||||
type Router interface {
|
||||
// mapPort creates a mapping between a port on the local computer to an
|
||||
// external port on the router.
|
||||
//
|
||||
// The mappingName is something displayed on the router, so it is included
|
||||
// for completeness.
|
||||
MapPort(
|
||||
networkProtocol NetworkProtocol,
|
||||
newInternalPort uint16,
|
||||
newExternalPort uint16,
|
||||
mappingName string,
|
||||
mappingDuration time.Duration) error
|
||||
|
||||
// UnmapPort clears a mapping that was previous made by a call to MapPort
|
||||
UnmapPort(
|
||||
networkProtocol NetworkProtocol,
|
||||
internalPort uint16,
|
||||
externalPort uint16) error
|
||||
|
||||
// Returns the routers IP address on the network the router considers
|
||||
// external
|
||||
IP() (net.IP, error)
|
||||
}
|
||||
|
||||
// NewRouter returns a new router discovered on the local network
|
||||
func NewRouter() Router {
|
||||
routers := make(chan Router)
|
||||
// Because getting a router can take a noticeable amount of time to error,
|
||||
// we run these requests in parallel
|
||||
go func() {
|
||||
routers <- getUPnPRouter()
|
||||
}()
|
||||
go func() {
|
||||
routers <- getPMPRouter()
|
||||
}()
|
||||
for i := 0; i < 2; i++ {
|
||||
if router := <-routers; router != nil {
|
||||
return router
|
||||
}
|
||||
}
|
||||
return noRouter{}
|
||||
}
|
219
nat/upnp.go
219
nat/upnp.go
|
@ -1,10 +1,6 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package nat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
@ -14,13 +10,7 @@ import (
|
|||
"github.com/huin/goupnp/dcps/internetgateway2"
|
||||
)
|
||||
|
||||
const (
|
||||
soapTimeout = time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
errNoGateway = errors.New("Failed to connect to any avaliable gateways")
|
||||
)
|
||||
const soapRequestTimeout = 3 * time.Second
|
||||
|
||||
// upnpClient is the interface used by goupnp for their client implementations
|
||||
type upnpClient interface {
|
||||
|
@ -50,66 +40,13 @@ type upnpClient interface {
|
|||
}
|
||||
|
||||
type upnpRouter struct {
|
||||
root *goupnp.RootDevice
|
||||
dev *goupnp.RootDevice
|
||||
client upnpClient
|
||||
}
|
||||
|
||||
func (n *upnpRouter) MapPort(
|
||||
networkProtocol NetworkProtocol,
|
||||
newInternalPort uint16,
|
||||
newExternalPort uint16,
|
||||
mappingName string,
|
||||
mappingDuration time.Duration,
|
||||
) error {
|
||||
ip, err := n.localAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
protocol := string(networkProtocol)
|
||||
// goupnp uses seconds to denote their lifetime
|
||||
lifetime := uint32(mappingDuration / time.Second)
|
||||
|
||||
// UnmapPort's error is intentionally dropped, because the mapping may not
|
||||
// exist.
|
||||
n.UnmapPort(networkProtocol, newInternalPort, newExternalPort)
|
||||
|
||||
return n.client.AddPortMapping(
|
||||
"", // newRemoteHost isn't used to limit the mapping to a host
|
||||
newExternalPort,
|
||||
protocol,
|
||||
newInternalPort,
|
||||
ip.String(), // newInternalClient is the client traffic should be sent to
|
||||
true, // newEnabled enables port mappings
|
||||
mappingName,
|
||||
lifetime,
|
||||
)
|
||||
}
|
||||
|
||||
func (n *upnpRouter) UnmapPort(networkProtocol NetworkProtocol, _, externalPort uint16) error {
|
||||
protocol := string(networkProtocol)
|
||||
return n.client.DeletePortMapping(
|
||||
"", // newRemoteHost isn't used to limit the mapping to a host
|
||||
externalPort,
|
||||
protocol)
|
||||
}
|
||||
|
||||
func (n *upnpRouter) IP() (net.IP, error) {
|
||||
ipStr, err := n.client.GetExternalIPAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid IP %s", ipStr)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (n *upnpRouter) localAddress() (net.IP, error) {
|
||||
func (r *upnpRouter) localIP() (net.IP, error) {
|
||||
// attempt to get an address on the router
|
||||
deviceAddr, err := net.ResolveUDPAddr("udp4", n.root.URLBase.Host)
|
||||
deviceAddr, err := net.ResolveUDPAddr("udp4", r.dev.URLBase.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -142,27 +79,34 @@ func (n *upnpRouter) localAddress() (net.IP, error) {
|
|||
}
|
||||
}
|
||||
return nil, fmt.Errorf("couldn't find the local address in the same network as %s", deviceIP)
|
||||
|
||||
}
|
||||
|
||||
// getUPnPRouter searches for all Gateway Devices that have avaliable
|
||||
// connections in the goupnp library and returns the first connection it can
|
||||
// find.
|
||||
func getUPnPRouter() Router {
|
||||
routers := make(chan *upnpRouter)
|
||||
// Because DiscoverDevices takes a noticeable amount of time to error, we
|
||||
// run these requests in parallel
|
||||
go func() {
|
||||
routers <- connectToGateway(internetgateway1.URN_WANConnectionDevice_1, gateway1)
|
||||
}()
|
||||
go func() {
|
||||
routers <- connectToGateway(internetgateway2.URN_WANConnectionDevice_2, gateway2)
|
||||
}()
|
||||
for i := 0; i < 2; i++ {
|
||||
if router := <-routers; router != nil {
|
||||
return router
|
||||
}
|
||||
func (r *upnpRouter) ExternalIP() (net.IP, error) {
|
||||
str, err := r.client.GetExternalIPAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil
|
||||
|
||||
ip := net.ParseIP(str)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("invalid IP %s", str)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func (r *upnpRouter) MapPort(protocol string, intport, extport uint16, desc string, duration time.Duration) error {
|
||||
ip, err := r.localIP()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
lifetime := uint32(duration / time.Second)
|
||||
r.UnmapPort(protocol, extport)
|
||||
return r.client.AddPortMapping("", extport, protocol, intport, ip.String(), true, desc, lifetime)
|
||||
}
|
||||
|
||||
func (r *upnpRouter) UnmapPort(protocol string, extport uint16) error {
|
||||
return r.client.DeletePortMapping("", extport, protocol)
|
||||
}
|
||||
|
||||
func gateway1(client goupnp.ServiceClient) upnpClient {
|
||||
|
@ -175,7 +119,6 @@ func gateway1(client goupnp.ServiceClient) upnpClient {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func gateway2(client goupnp.ServiceClient) upnpClient {
|
||||
switch client.Service.ServiceType {
|
||||
case internetgateway2.URN_WANIPConnection_1:
|
||||
|
@ -189,65 +132,69 @@ func gateway2(client goupnp.ServiceClient) upnpClient {
|
|||
}
|
||||
}
|
||||
|
||||
func connectToGateway(deviceType string, toClient func(goupnp.ServiceClient) upnpClient) *upnpRouter {
|
||||
devs, err := goupnp.DiscoverDevices(deviceType)
|
||||
func getUpnpClient(client goupnp.ServiceClient) upnpClient {
|
||||
c := gateway1(client)
|
||||
if c != nil {
|
||||
return c
|
||||
}
|
||||
return gateway2(client)
|
||||
}
|
||||
|
||||
func getRootDevice(dev *goupnp.MaybeRootDevice) *upnpRouter {
|
||||
var router *upnpRouter
|
||||
dev.Root.Device.VisitServices(func(service *goupnp.Service) {
|
||||
c := goupnp.ServiceClient{
|
||||
SOAPClient: service.NewSOAPClient(),
|
||||
RootDevice: dev.Root,
|
||||
Location: dev.Location,
|
||||
Service: service,
|
||||
}
|
||||
c.SOAPClient.HTTPClient.Timeout = soapRequestTimeout
|
||||
client := getUpnpClient(c)
|
||||
if client == nil {
|
||||
return
|
||||
}
|
||||
router = &upnpRouter{dev.Root, client}
|
||||
if router == nil {
|
||||
return
|
||||
}
|
||||
if _, nat, err := router.client.GetNATRSIPStatus(); err != nil || !nat {
|
||||
router = nil
|
||||
return
|
||||
}
|
||||
})
|
||||
return router
|
||||
}
|
||||
|
||||
func discover(target string) *upnpRouter {
|
||||
devs, err := goupnp.DiscoverDevices(target)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// we are iterating over all the network devices, acting a possible roots
|
||||
for i := range devs {
|
||||
dev := &devs[i]
|
||||
if dev.Root == nil {
|
||||
for i := 0; i < len(devs); i++ {
|
||||
if devs[i].Root == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// the root device may be a router, so attempt to connect to that
|
||||
rootDevice := &dev.Root.Device
|
||||
if upnp := getRouter(dev, rootDevice, toClient); upnp != nil {
|
||||
return upnp
|
||||
}
|
||||
|
||||
// attempt to connect to any sub devices
|
||||
devices := rootDevice.Devices
|
||||
for i := range devices {
|
||||
if upnp := getRouter(dev, &devices[i], toClient); upnp != nil {
|
||||
return upnp
|
||||
}
|
||||
u := getRootDevice(&devs[i])
|
||||
if u != nil {
|
||||
return u
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRouter(rootDevice *goupnp.MaybeRootDevice, device *goupnp.Device, toClient func(goupnp.ServiceClient) upnpClient) *upnpRouter {
|
||||
for i := range device.Services {
|
||||
service := &device.Services[i]
|
||||
|
||||
soapClient := service.NewSOAPClient()
|
||||
// make sure the client times out if needed
|
||||
soapClient.HTTPClient.Timeout = soapTimeout
|
||||
|
||||
// attempt to create a client connection
|
||||
serviceClient := goupnp.ServiceClient{
|
||||
SOAPClient: soapClient,
|
||||
RootDevice: rootDevice.Root,
|
||||
Location: rootDevice.Location,
|
||||
Service: service,
|
||||
}
|
||||
client := toClient(serviceClient)
|
||||
if client == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// check whether port mapping is enabled
|
||||
if _, nat, err := client.GetNATRSIPStatus(); err != nil || !nat {
|
||||
continue
|
||||
}
|
||||
|
||||
// we found a router!
|
||||
return &upnpRouter{
|
||||
root: rootDevice.Root,
|
||||
client: client,
|
||||
}
|
||||
func getUPnPRouter() *upnpRouter {
|
||||
r := discover(internetgateway1.URN_WANConnectionDevice_1)
|
||||
if r != nil {
|
||||
return r
|
||||
}
|
||||
return nil
|
||||
return discover(internetgateway2.URN_WANConnectionDevice_2)
|
||||
}
|
||||
|
||||
func GetUPnP() *upnpRouter {
|
||||
r := discover(internetgateway1.URN_WANConnectionDevice_1)
|
||||
if r != nil {
|
||||
return r
|
||||
}
|
||||
return discover(internetgateway2.URN_WANConnectionDevice_2)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
// Config contains all of the configurations of an Ava node.
|
||||
type Config struct {
|
||||
// protocol to use for opening the network interface
|
||||
Nat nat.Router
|
||||
Nat nat.NATRouter
|
||||
|
||||
// ID of the network this node should connect to
|
||||
NetworkID uint32
|
||||
|
|
Loading…
Reference in New Issue