bring pmp back

This commit is contained in:
Hongbo Zhang 2020-06-15 15:16:24 -04:00
parent fb51e6a443
commit 571b6e597b
4 changed files with 100 additions and 14 deletions

View File

@ -1,3 +1,6 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nat package nat
import ( import (
@ -10,14 +13,14 @@ import (
) )
const ( const (
mapTimeout = 30 * time.Minute mapTimeout = 30 * time.Second
mapUpdateTimeout = mapTimeout / 2 mapUpdateTimeout = mapTimeout / 2
maxRetries = 20 maxRetries = 20
) )
type NATRouter interface { type NATRouter interface {
MapPort(protocol string, intPort, extPort uint16, desc string, duration time.Duration) error MapPort(protocol string, intPort, extPort uint16, desc string, duration time.Duration) error
UnmapPort(protocol string, extPort uint16) error UnmapPort(protocol string, intPort, extPort uint16) error
ExternalIP() (net.IP, error) ExternalIP() (net.IP, error)
GetPortMappingEntry(extPort uint16, protocol string) ( GetPortMappingEntry(extPort uint16, protocol string) (
InternalIP string, InternalIP string,
@ -28,10 +31,12 @@ type NATRouter interface {
} }
func GetNATRouter() NATRouter { func GetNATRouter() NATRouter {
//TODO add PMP support
if r := getUPnPRouter(); r != nil { if r := getUPnPRouter(); r != nil {
return r return r
} }
if r := getPMPRouter(); r != nil {
return r
}
return NewNoRouter() return NewNoRouter()
} }
@ -95,11 +100,9 @@ func (dev *Mapper) keepPortMapping(mappedPort chan<- uint16, protocol string,
updateTimer.Stop() updateTimer.Stop()
dev.log.Info("Unmap protocol %s external port %d", protocol, port) dev.log.Info("Unmap protocol %s external port %d", protocol, port)
if port > 0 { dev.errLock.Lock()
dev.errLock.Lock() dev.errs.Add(dev.r.UnmapPort(protocol, intPort, port))
dev.errs.Add(dev.r.UnmapPort(protocol, port)) dev.errLock.Unlock()
dev.errLock.Unlock()
}
dev.wg.Done() dev.wg.Done()
}(port) }(port)
@ -120,7 +123,6 @@ func (dev *Mapper) keepPortMapping(mappedPort chan<- uint16, protocol string,
return return
} }
} }
break
} }
} }

View File

@ -1,3 +1,6 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nat package nat
import ( import (
@ -12,14 +15,14 @@ type noRouter struct {
ip net.IP ip net.IP
} }
func (noRouter) MapPort(protocol string, intport, extport uint16, desc string, duration time.Duration) error { func (noRouter) MapPort(_ string, intPort, extPort uint16, _ string, _ time.Duration) error {
if intport != extport { if intPort != extPort {
return fmt.Errorf("cannot map port %d to %d", intport, extport) return fmt.Errorf("cannot map port %d to %d", intPort, extPort)
} }
return nil return nil
} }
func (noRouter) UnmapPort(protocol string, extport uint16) error { func (noRouter) UnmapPort(string, uint16, uint16) error {
return nil return nil
} }

78
nat/pmp.go Normal file
View File

@ -0,0 +1,78 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nat
import (
"fmt"
"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 pmpRouter struct {
client *natpmp.Client
}
func (pmp *pmpRouter) MapPort(
networkProtocol string,
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 *pmpRouter) UnmapPort(
networkProtocol string,
internalPort uint16,
_ uint16) error {
protocol := string(networkProtocol)
internalPortInt := int(internalPort)
_, err := pmp.client.AddPortMapping(protocol, internalPortInt, 0, 0)
return err
}
func (pmp *pmpRouter) ExternalIP() (net.IP, error) {
response, err := pmp.client.GetExternalAddress()
if err != nil {
return nil, err
}
return response.ExternalIPAddress[:], nil
}
// go-nat-pmp does not support port mapping entry query
func (pmp *pmpRouter) GetPortMappingEntry(externalPort uint16, protocol string) (
string, uint16, string, error) {
return "", 0, "", fmt.Errorf("port mapping entry not found")
}
func getPMPRouter() *pmpRouter {
gatewayIP, err := gateway.DiscoverGateway()
if err != nil {
return nil
}
pmp := &pmpRouter{natpmp.NewClientWithTimeout(gatewayIP, pmpClientTimeout)}
if _, err := pmp.ExternalIP(); err != nil {
return nil
}
return pmp
}

View File

@ -1,3 +1,6 @@
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package nat package nat
import ( import (
@ -119,7 +122,7 @@ func (r *upnpRouter) MapPort(protocol string, intPort, extPort uint16,
ip.String(), true, desc, lifetime) ip.String(), true, desc, lifetime)
} }
func (r *upnpRouter) UnmapPort(protocol string, extPort uint16) error { func (r *upnpRouter) UnmapPort(protocol string, _, extPort uint16) error {
return r.client.DeletePortMapping("", extPort, protocol) return r.client.DeletePortMapping("", extPort, protocol)
} }