staking internal port and external port could be different

get mapped port entry; change interface to mapper
This commit is contained in:
Hongbo Zhang 2020-06-14 03:51:31 -04:00
parent f8301f11c2
commit 3cfba77c70
7 changed files with 63 additions and 95 deletions

View File

@ -68,11 +68,11 @@ func main() {
log.Debug("assertions are enabled. This may slow down execution")
}
router := nat.NewRouter(log, Config.Nat)
defer router.UnmapAllPorts()
mapper := nat.NewPortMapper(log, Config.Nat)
defer mapper.UnmapAllPorts()
router.Map("TCP", Config.StakingIP.Port, Config.StakingIP.Port, "gecko")
router.Map("TCP", Config.HTTPPort, Config.HTTPPort, "gecko http")
Config.StakingIP.Port = mapper.Map("TCP", Config.StakingLocalPort, Config.StakingIP.Port, "gecko")
Config.HTTPPort = mapper.Map("TCP", Config.HTTPPort, Config.HTTPPort, "gecko http")
node := node.Node{}

View File

@ -303,6 +303,7 @@ func init() {
IP: ip,
Port: uint16(*consensusPort),
}
Config.StakingLocalPort = uint16(*consensusPort)
defaultBootstrapIPs, defaultBootstrapIDs := GetDefaultBootstraps(networkID, 5)

View File

@ -19,7 +19,12 @@ 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)
IsMapped(extport uint16, protocol string) bool
GetPortMappingEntry(extport uint16, protocol string) (
InternalIP string,
InternalPort uint16,
Description string,
err error,
)
}
func GetNATRouter() NATRouter {
@ -31,7 +36,7 @@ func GetNATRouter() NATRouter {
return NewNoRouter()
}
type Router struct {
type Mapper struct {
log logging.Logger
r NATRouter
closer chan struct{}
@ -40,8 +45,8 @@ type Router struct {
errs wrappers.Errs
}
func NewRouter(log logging.Logger, r NATRouter) Router {
return Router{
func NewPortMapper(log logging.Logger, r NATRouter) Mapper {
return Mapper{
log: log,
r: r,
closer: make(chan struct{}),
@ -51,7 +56,7 @@ func NewRouter(log logging.Logger, r NATRouter) Router {
// Map sets up port mapping using given protocol, internal and external ports
// and returns the final port mapped. It returns 0 if mapping failed after the
// maximun number of retries
func (dev *Router) Map(protocol string, intport, extport uint16, desc string) uint16 {
func (dev *Mapper) Map(protocol string, intport, extport uint16, desc string) uint16 {
mappedPort := make(chan uint16)
dev.wg.Add(1)
@ -62,7 +67,7 @@ func (dev *Router) Map(protocol string, intport, extport uint16, desc string) ui
// keepPortMapping runs in the background to keep a port mapped. It renews the
// the port mapping in mapUpdateTimeout.
func (dev *Router) keepPortMapping(mappedPort chan<- uint16, protocol string,
func (dev *Mapper) keepPortMapping(mappedPort chan<- uint16, protocol string,
intport, extport uint16, desc string) {
updateTimer := time.NewTimer(mapUpdateTimeout)
var port uint16 = 0
@ -82,8 +87,9 @@ func (dev *Router) keepPortMapping(mappedPort chan<- uint16, protocol string,
for i := 0; i < maxRetries; i++ {
port = extport + uint16(i)
if dev.r.IsMapped(port, protocol) {
dev.log.Info("Port %d is occupied, retry with the next port", port)
if intaddr, intport, desc, err := dev.r.GetPortMappingEntry(port, protocol); err == nil {
dev.log.Info("Port %d is mapped to %s:%d: %s, retry with the next port",
port, intaddr, intport, desc)
continue
}
if err := dev.r.MapPort(protocol, intport, port, desc, mapTimeout); err != nil {
@ -124,7 +130,7 @@ func (dev *Router) keepPortMapping(mappedPort chan<- uint16, protocol string,
}
}
func (dev *Router) UnmapAllPorts() error {
func (dev *Mapper) UnmapAllPorts() error {
close(dev.closer)
dev.wg.Wait()
dev.log.Info("Unmapped all ports")

View File

@ -27,8 +27,8 @@ func (r noRouter) ExternalIP() (net.IP, error) {
return r.ip, nil
}
func (noRouter) IsMapped(uint16, string) bool {
return false
func (noRouter) GetPortMappingEntry(uint16, string) (string, uint16, string, error) {
return "", 0, "", nil
}
func getOutboundIP() (net.IP, error) {

View File

@ -62,7 +62,7 @@ type upnpRouter struct {
func (r *upnpRouter) localIP() (net.IP, error) {
// attempt to get an address on the router
deviceAddr, err := net.ResolveUDPAddr("udp4", r.dev.URLBase.Host)
deviceAddr, err := net.ResolveUDPAddr("udp", r.dev.URLBase.Host)
if err != nil {
return nil, err
}
@ -73,7 +73,7 @@ func (r *upnpRouter) localIP() (net.IP, error) {
return nil, err
}
// attempt to find one of my ips that the router would know about
// attempt to find one of my IPs that matches router's record
for _, netInterface := range netInterfaces {
addrs, err := netInterface.Addrs()
if err != nil {
@ -123,102 +123,62 @@ func (r *upnpRouter) UnmapPort(protocol string, extport uint16) error {
return r.client.DeletePortMapping("", extport, protocol)
}
func (r *upnpRouter) IsMapped(extport uint16, protocol string) bool {
_, _, enabled, _, _, _ := r.client.GetSpecificPortMappingEntry("", extport, protocol)
return enabled
func (r *upnpRouter) GetPortMappingEntry(extport uint16, protocol string) (string, uint16, string, error) {
intport, intaddr, _, desc, _, err := r.client.GetSpecificPortMappingEntry("", extport, protocol)
return intaddr, intport, desc, err
}
func gateway1(client goupnp.ServiceClient) upnpClient {
// create UPnP SOAP service client with URN
func getUPnPClient(client goupnp.ServiceClient) upnpClient {
switch client.Service.ServiceType {
case internetgateway1.URN_WANIPConnection_1:
return &internetgateway1.WANIPConnection1{ServiceClient: client}
case internetgateway1.URN_WANPPPConnection_1:
return &internetgateway1.WANPPPConnection1{ServiceClient: client}
default:
return nil
}
}
func gateway2(client goupnp.ServiceClient) upnpClient {
switch client.Service.ServiceType {
case internetgateway2.URN_WANIPConnection_1:
return &internetgateway2.WANIPConnection1{ServiceClient: client}
case internetgateway2.URN_WANIPConnection_2:
return &internetgateway2.WANIPConnection2{ServiceClient: client}
case internetgateway2.URN_WANPPPConnection_1:
return &internetgateway2.WANPPPConnection1{ServiceClient: client}
default:
return nil
}
}
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
}
// discover() tries to find gateway device
func discover(target string) *upnpRouter {
devs, err := goupnp.DiscoverDevices(target)
if err != nil {
return nil
}
router := make(chan *upnpRouter)
for i := 0; i < len(devs); i++ {
if devs[i].Root == nil {
continue
}
u := getRootDevice(&devs[i])
if u != nil {
return u
}
}
return gateway2(client)
}
func getUPnPRouter() *upnpRouter {
targets := []string{
internetgateway1.URN_WANConnectionDevice_1,
internetgateway2.URN_WANConnectionDevice_2,
go func(dev *goupnp.MaybeRootDevice) {
var r *upnpRouter = nil
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
}
if _, nat, err := client.GetNATRSIPStatus(); err != nil || !nat {
return
}
r = &upnpRouter{dev.Root, client}
})
router <- r
}(&devs[i])
}
routers := make(chan *upnpRouter, len(targets))
for _, urn := range targets {
go func(urn string) {
routers <- discover(urn)
}(urn)
}
for i := 0; i < len(targets); i++ {
if r := <-routers; r != nil {
for i := 0; i < len(devs); i++ {
if r := <-router; r != nil {
return r
}
}
@ -234,7 +194,7 @@ func getUPnPRouter() *upnpRouter {
internetgateway2.URN_WANConnectionDevice_2,
}
routers := make(chan *upnpRouter, len(targets))
routers := make(chan *upnpRouter)
for _, urn := range targets {
go func(urn string) {

View File

@ -33,11 +33,12 @@ type Config struct {
DB database.Database
// Staking configuration
StakingIP utils.IPDesc
EnableP2PTLS bool
EnableStaking bool
StakingKeyFile string
StakingCertFile string
StakingIP utils.IPDesc
StakingLocalPort uint16
EnableP2PTLS bool
EnableStaking bool
StakingKeyFile string
StakingCertFile string
// Bootstrapping configuration
BootstrapPeers []*Peer

View File

@ -112,7 +112,7 @@ type Node struct {
*/
func (n *Node) initNetworking() error {
listener, err := net.Listen(TCP, n.Config.StakingIP.PortString())
listener, err := net.Listen(TCP, fmt.Sprintf(":%d", n.Config.StakingLocalPort))
if err != nil {
return err
}