mirror of
https://github.com/fatedier/frp.git
synced 2025-06-17 17:18:21 +00:00
Merge 5d8710561958ecbbbf4d0c07c1e34b40781d6976 into f3a71bc08f0e606ff407638a34ddf09ecffe2364
This commit is contained in:
commit
94879e7c91
@ -28,6 +28,7 @@ import (
|
|||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/msg"
|
"github.com/fatedier/frp/pkg/msg"
|
||||||
"github.com/fatedier/frp/pkg/nathole"
|
"github.com/fatedier/frp/pkg/nathole"
|
||||||
|
"github.com/fatedier/frp/pkg/nathole/upnp"
|
||||||
"github.com/fatedier/frp/pkg/transport"
|
"github.com/fatedier/frp/pkg/transport"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
)
|
)
|
||||||
@ -53,6 +54,23 @@ func NewXTCPProxy(baseProxy *BaseProxy, cfg v1.ProxyConfigurer) Proxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pxy *XTCPProxy) makeRouterToNatThisHole(remoteGetAddrs []string, localIps []string, localAddr net.Addr) {
|
||||||
|
|
||||||
|
xl := pxy.xl
|
||||||
|
if !pxy.cfg.AllowToUseUPNP {
|
||||||
|
xl.Tracef("makeRouterToNatThisHole: upnp disabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
description := pxy.cfg.UPNPPortMappingDescription
|
||||||
|
if description == "" {
|
||||||
|
description = upnp.DEFAULT_UPNP_PROGRAM_DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
upnp.AskForMapping(xl, remoteGetAddrs, localIps, localAddr, description)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkConn) {
|
func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkConn) {
|
||||||
xl := pxy.xl
|
xl := pxy.xl
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
@ -64,7 +82,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, startWorkConnMsg *msg.StartWorkC
|
|||||||
}
|
}
|
||||||
|
|
||||||
xl.Tracef("nathole prepare start")
|
xl.Tracef("nathole prepare start")
|
||||||
prepareResult, err := nathole.Prepare([]string{pxy.clientCfg.NatHoleSTUNServer})
|
prepareResult, err := nathole.Prepare([]string{pxy.clientCfg.NatHoleSTUNServer}, pxy.makeRouterToNatThisHole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xl.Warnf("nathole prepare error: %v", err)
|
xl.Warnf("nathole prepare error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/msg"
|
"github.com/fatedier/frp/pkg/msg"
|
||||||
"github.com/fatedier/frp/pkg/nathole"
|
"github.com/fatedier/frp/pkg/nathole"
|
||||||
|
"github.com/fatedier/frp/pkg/nathole/upnp"
|
||||||
"github.com/fatedier/frp/pkg/transport"
|
"github.com/fatedier/frp/pkg/transport"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
"github.com/fatedier/frp/pkg/util/util"
|
"github.com/fatedier/frp/pkg/util/util"
|
||||||
@ -261,6 +262,23 @@ func (sv *XTCPVisitor) getTunnelConn() (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sv *XTCPVisitor) makeRouterToNatThisHole(remoteGetAddrs []string, localIps []string, localAddr net.Addr) {
|
||||||
|
|
||||||
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
|
if !sv.cfg.AllowToUseUPNP {
|
||||||
|
xl.Tracef("makeRouterToNatThisHole: upnp disabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
description := sv.cfg.UPNPPortMappingDescription
|
||||||
|
if description == "" {
|
||||||
|
description = upnp.DEFAULT_UPNP_PROGRAM_DESCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
upnp.AskForMapping(xl, remoteGetAddrs, localIps, localAddr, description)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 0. PreCheck
|
// 0. PreCheck
|
||||||
// 1. Prepare
|
// 1. Prepare
|
||||||
// 2. ExchangeInfo
|
// 2. ExchangeInfo
|
||||||
@ -275,7 +293,7 @@ func (sv *XTCPVisitor) makeNatHole() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
xl.Tracef("nathole prepare start")
|
xl.Tracef("nathole prepare start")
|
||||||
prepareResult, err := nathole.Prepare([]string{sv.clientCfg.NatHoleSTUNServer})
|
prepareResult, err := nathole.Prepare([]string{sv.clientCfg.NatHoleSTUNServer}, sv.makeRouterToNatThisHole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
xl.Warnf("nathole prepare error: %v", err)
|
xl.Warnf("nathole prepare error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -336,6 +336,9 @@ localPort = 22
|
|||||||
# If not empty, only visitors from specified users can connect.
|
# If not empty, only visitors from specified users can connect.
|
||||||
# Otherwise, visitors from same user can connect. '*' means allow all users.
|
# Otherwise, visitors from same user can connect. '*' means allow all users.
|
||||||
allowUsers = ["user1", "user2"]
|
allowUsers = ["user1", "user2"]
|
||||||
|
# allow to use upnp to map this port
|
||||||
|
allowToUseUPNP = false
|
||||||
|
upnpPortMappingDescription = "helper-port-mapping"
|
||||||
|
|
||||||
# frpc role visitor -> frps -> frpc role server
|
# frpc role visitor -> frps -> frpc role server
|
||||||
[[visitors]]
|
[[visitors]]
|
||||||
@ -368,3 +371,5 @@ maxRetriesAnHour = 8
|
|||||||
minRetryInterval = 90
|
minRetryInterval = 90
|
||||||
# fallbackTo = "stcp_visitor"
|
# fallbackTo = "stcp_visitor"
|
||||||
# fallbackTimeoutMs = 500
|
# fallbackTimeoutMs = 500
|
||||||
|
allowToUseUPNP = false
|
||||||
|
upnpPortMappingDescription = "helper-port-mapping"
|
||||||
|
3
go.mod
3
go.mod
@ -46,7 +46,9 @@ require (
|
|||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||||
|
github.com/huin/goupnp v1.3.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jackpal/gateway v1.0.14 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||||
github.com/klauspost/reedsolomon v1.12.0 // indirect
|
github.com/klauspost/reedsolomon v1.12.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
@ -60,6 +62,7 @@ require (
|
|||||||
github.com/prometheus/common v0.48.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
|
github.com/stretchr/objx v0.5.0 // indirect
|
||||||
github.com/templexxx/cpu v0.1.0 // indirect
|
github.com/templexxx/cpu v0.1.0 // indirect
|
||||||
github.com/templexxx/xorsimd v0.4.2 // indirect
|
github.com/templexxx/xorsimd v0.4.2 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
|
6
go.sum
6
go.sum
@ -66,9 +66,13 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
|||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||||
|
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jackpal/gateway v1.0.14 h1:6ZfIuFvnvWrS59hHbvZGR/R33ojV2LASBODomt7zlJU=
|
||||||
|
github.com/jackpal/gateway v1.0.14/go.mod h1:6c8LjW+FVESFmwxaXySkt7fU98Yv806ADS3OY6Cvh2U=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
|
github.com/klauspost/reedsolomon v1.12.0 h1:I5FEp3xSwVCcEh3F5A7dofEfhXdF/bWhQWPH+XwBFno=
|
||||||
@ -127,6 +131,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
@ -194,6 +199,7 @@ golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2
|
|||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
|
@ -134,3 +134,8 @@ type HTTPHeader struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type XTCPConfigUPNPMixin struct {
|
||||||
|
AllowToUseUPNP bool `json:"allowToUseUPNP,omitempty"`
|
||||||
|
UPNPPortMappingDescription string `json:"upnpPortMappingDescription,omitempty"`
|
||||||
|
}
|
||||||
|
@ -411,6 +411,8 @@ type XTCPProxyConfig struct {
|
|||||||
|
|
||||||
Secretkey string `json:"secretKey,omitempty"`
|
Secretkey string `json:"secretKey,omitempty"`
|
||||||
AllowUsers []string `json:"allowUsers,omitempty"`
|
AllowUsers []string `json:"allowUsers,omitempty"`
|
||||||
|
|
||||||
|
XTCPConfigUPNPMixin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *XTCPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
|
func (c *XTCPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
|
||||||
|
@ -153,6 +153,8 @@ type XTCPVisitorConfig struct {
|
|||||||
MinRetryInterval int `json:"minRetryInterval,omitempty"`
|
MinRetryInterval int `json:"minRetryInterval,omitempty"`
|
||||||
FallbackTo string `json:"fallbackTo,omitempty"`
|
FallbackTo string `json:"fallbackTo,omitempty"`
|
||||||
FallbackTimeoutMs int `json:"fallbackTimeoutMs,omitempty"`
|
FallbackTimeoutMs int `json:"fallbackTimeoutMs,omitempty"`
|
||||||
|
|
||||||
|
XTCPConfigUPNPMixin
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *XTCPVisitorConfig) Complete(g *ClientCommonConfig) {
|
func (c *XTCPVisitorConfig) Complete(g *ClientCommonConfig) {
|
||||||
|
@ -107,8 +107,12 @@ func PreCheck(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OnGetMyRemoteAddress func(remoteGetAddrs []string, localIps []string, localAddr net.Addr)
|
||||||
|
|
||||||
// Prepare is used to do some preparation work before penetration.
|
// Prepare is used to do some preparation work before penetration.
|
||||||
func Prepare(stunServers []string) (*PrepareResult, error) {
|
func Prepare(stunServers []string,
|
||||||
|
callback OnGetMyRemoteAddress,
|
||||||
|
) (*PrepareResult, error) {
|
||||||
// discover for Nat type
|
// discover for Nat type
|
||||||
addrs, localAddr, err := Discover(stunServers, "")
|
addrs, localAddr, err := Discover(stunServers, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -119,6 +123,11 @@ func Prepare(stunServers []string) (*PrepareResult, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localIPs, _ := ListLocalIPsForNatHole(10)
|
localIPs, _ := ListLocalIPsForNatHole(10)
|
||||||
|
|
||||||
|
if callback != nil {
|
||||||
|
callback(addrs, localIPs, localAddr)
|
||||||
|
}
|
||||||
|
|
||||||
natFeature, err := ClassifyNATFeature(addrs, localIPs)
|
natFeature, err := ClassifyNATFeature(addrs, localIPs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("classify nat feature error: %v", err)
|
return nil, fmt.Errorf("classify nat feature error: %v", err)
|
||||||
|
173
pkg/nathole/upnp/upnp.go
Normal file
173
pkg/nathole/upnp/upnp.go
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
package upnp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
"github.com/fatedier/frp/pkg/util/xlog"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/huin/goupnp/dcps/internetgateway2"
|
||||||
|
"github.com/jackpal/gateway"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DEFAULT_UPNP_PROGRAM_DESCRIPTION = "helper-port-mapping"
|
||||||
|
|
||||||
|
type RouterClient interface {
|
||||||
|
AddPortMapping(
|
||||||
|
NewRemoteHost string,
|
||||||
|
NewExternalPort uint16,
|
||||||
|
NewProtocol string,
|
||||||
|
NewInternalPort uint16,
|
||||||
|
NewInternalClient string,
|
||||||
|
NewEnabled bool,
|
||||||
|
NewPortMappingDescription string,
|
||||||
|
NewLeaseDuration uint32,
|
||||||
|
) (err error)
|
||||||
|
|
||||||
|
GetExternalIPAddress() (
|
||||||
|
NewExternalIPAddress string,
|
||||||
|
err error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PickRouterClient(ctx context.Context) (RouterClient, error) {
|
||||||
|
tasks, _ := errgroup.WithContext(ctx)
|
||||||
|
// Request each type of client in parallel, and return what is found.
|
||||||
|
var ip1Clients []*internetgateway2.WANIPConnection1
|
||||||
|
tasks.Go(func() error {
|
||||||
|
var err error
|
||||||
|
ip1Clients, _, err = internetgateway2.NewWANIPConnection1Clients()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
var ip2Clients []*internetgateway2.WANIPConnection2
|
||||||
|
tasks.Go(func() error {
|
||||||
|
var err error
|
||||||
|
ip2Clients, _, err = internetgateway2.NewWANIPConnection2Clients()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
var ppp1Clients []*internetgateway2.WANPPPConnection1
|
||||||
|
tasks.Go(func() error {
|
||||||
|
var err error
|
||||||
|
ppp1Clients, _, err = internetgateway2.NewWANPPPConnection1Clients()
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := tasks.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trivial handling for where we find exactly one device to talk to, you
|
||||||
|
// might want to provide more flexible handling than this if multiple
|
||||||
|
// devices are found.
|
||||||
|
switch {
|
||||||
|
case len(ip2Clients) == 1:
|
||||||
|
return ip2Clients[0], nil
|
||||||
|
case len(ip1Clients) == 1:
|
||||||
|
return ip1Clients[0], nil
|
||||||
|
case len(ppp1Clients) == 1:
|
||||||
|
return ppp1Clients[0], nil
|
||||||
|
default:
|
||||||
|
return nil, errors.New("multiple or no services found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UPNP_ForwardPort(ctx context.Context,
|
||||||
|
NewRemoteHost string,
|
||||||
|
NewExternalPort uint16,
|
||||||
|
NewProtocol string,
|
||||||
|
NewInternalPort uint16,
|
||||||
|
NewInternalClient string,
|
||||||
|
NewPortMappingDescription string,
|
||||||
|
NewLeaseDuration uint32,
|
||||||
|
) error {
|
||||||
|
client, err := PickRouterClient(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.AddPortMapping(
|
||||||
|
NewRemoteHost,
|
||||||
|
// External port number to expose to Internet:
|
||||||
|
NewExternalPort,
|
||||||
|
// Forward TCP (this could be "UDP" if we wanted that instead).
|
||||||
|
NewProtocol,
|
||||||
|
// Internal port number on the LAN to forward to.
|
||||||
|
// Some routers might not support this being different to the external
|
||||||
|
// port number.
|
||||||
|
NewInternalPort,
|
||||||
|
// Internal address on the LAN we want to forward to.
|
||||||
|
NewInternalClient,
|
||||||
|
// Enabled:
|
||||||
|
true,
|
||||||
|
// Informational description for the client requesting the port forwarding.
|
||||||
|
NewPortMappingDescription,
|
||||||
|
// How long should the port forward last for in seconds.
|
||||||
|
// If you want to keep it open for longer and potentially across router
|
||||||
|
// resets, you might want to periodically request before this elapses.
|
||||||
|
NewLeaseDuration,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AskForMapping(xl *xlog.Logger, remoteGetAddrs []string, localIps []string, localAddr net.Addr, description string) {
|
||||||
|
|
||||||
|
xl.Tracef("makeRouterToNatThisHole: %v, localIps %v, localAddr=%v", remoteGetAddrs, localIps, localAddr.String())
|
||||||
|
|
||||||
|
targetAddr := remoteGetAddrs[0]
|
||||||
|
remoteAddrPort, err := netip.ParseAddrPort(targetAddr)
|
||||||
|
if err != nil {
|
||||||
|
xl.Errorf("netip.ParseAddrPort error: %v. parse: %v", err, targetAddr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
localAddrStr := localAddr.String()
|
||||||
|
localAddrPort, err := netip.ParseAddrPort(localAddrStr)
|
||||||
|
if err != nil {
|
||||||
|
xl.Errorf("netip.ParseAddrPort local error: %v. parse: %v", err, localAddrStr)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetForwardTo := ""
|
||||||
|
if len(localIps) == 1 {
|
||||||
|
targetForwardTo = localIps[0]
|
||||||
|
} else {
|
||||||
|
targetForwardToIp, err := gateway.DiscoverInterface()
|
||||||
|
if err != nil {
|
||||||
|
xl.Warnf("load Default interface error:%v", err)
|
||||||
|
} else {
|
||||||
|
targetForwardTo = targetForwardToIp.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetForwardTo == "" && len(localIps) > 1 {
|
||||||
|
targetForwardTo = localIps[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||||
|
|
||||||
|
xl.Infof("UPNP_ForwardPort: remoteAddrPort=%v, localAddrPort=%v, targetForwardToLocal=%v", remoteAddrPort, localAddrPort, targetForwardTo)
|
||||||
|
err = UPNP_ForwardPort(
|
||||||
|
ctx,
|
||||||
|
/*NewRemoteHost*/ remoteAddrPort.Addr().String(),
|
||||||
|
/*NewExternalPort*/ remoteAddrPort.Port(),
|
||||||
|
/*NewProtocol*/ "UDP",
|
||||||
|
|
||||||
|
/*NewInternalPort*/
|
||||||
|
localAddrPort.Port(),
|
||||||
|
/*NewInternalClient*/ targetForwardTo,
|
||||||
|
/*NewPortMappingDescription*/ description,
|
||||||
|
/*NewLeaseDuration*/ 360,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
xl.Warnf("UPNP_ForwardPort error: %v.", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
xl.Tracef("UPNP_ForwardPort done")
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user