server/proxy: simplify the code (#3488)

This commit is contained in:
fatedier 2023-06-16 00:14:19 +08:00 committed by GitHub
parent 9ba6a06470
commit e1cef053be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 235 additions and 173 deletions

View File

@ -130,6 +130,7 @@ func (c *Controller) ListenClient(name string, sk string, allowUsers []string) c
} }
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
// TODO(fatedier): return error if name already exists
c.clientCfgs[name] = cfg c.clientCfgs[name] = cfg
return cfg.sidCh return cfg.sidCh
} }

View File

@ -17,10 +17,10 @@ package proxy
import ( import (
"io" "io"
"net" "net"
"reflect"
"strings" "strings"
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/limit" "github.com/fatedier/frp/pkg/util/limit"
@ -30,6 +30,10 @@ import (
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.HTTPProxyConf{}), NewHTTPProxy)
}
type HTTPProxy struct { type HTTPProxy struct {
*BaseProxy *BaseProxy
cfg *config.HTTPProxyConf cfg *config.HTTPProxyConf
@ -37,6 +41,17 @@ type HTTPProxy struct {
closeFuncs []func() closeFuncs []func()
} }
func NewHTTPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.HTTPProxyConf)
if !ok {
return nil
}
return &HTTPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *HTTPProxy) Run() (remoteAddr string, err error) { func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
routeConfig := vhost.RouteConfig{ routeConfig := vhost.RouteConfig{
@ -137,10 +152,6 @@ func (pxy *HTTPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) { func (pxy *HTTPProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) {
xl := pxy.xl xl := pxy.xl
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr) rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr)

View File

@ -15,20 +15,34 @@
package proxy package proxy
import ( import (
"reflect"
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.HTTPSProxyConf{}), NewHTTPSProxy)
}
type HTTPSProxy struct { type HTTPSProxy struct {
*BaseProxy *BaseProxy
cfg *config.HTTPSProxyConf cfg *config.HTTPSProxyConf
} }
func NewHTTPSProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.HTTPSProxyConf)
if !ok {
return nil
}
return &HTTPSProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) { func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
routeConfig := &vhost.RouteConfig{} routeConfig := &vhost.RouteConfig{}
@ -67,7 +81,7 @@ func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort)) addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPSPort))
} }
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startCommonTCPListenersHandler()
remoteAddr = strings.Join(addrs, ",") remoteAddr = strings.Join(addrs, ",")
return return
} }
@ -76,10 +90,6 @@ func (pxy *HTTPSProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *HTTPSProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *HTTPSProxy) Close() { func (pxy *HTTPSProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@ -19,6 +19,7 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"reflect"
"strconv" "strconv"
"sync" "sync"
"time" "time"
@ -36,6 +37,12 @@ import (
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
) )
var proxyFactoryRegistry = map[reflect.Type]func(*BaseProxy, config.ProxyConf) Proxy{}
func RegisterProxyFactory(proxyConfType reflect.Type, factory func(*BaseProxy, config.ProxyConf) Proxy) {
proxyFactoryRegistry[proxyConfType] = factory
}
type GetWorkConnFn func() (net.Conn, error) type GetWorkConnFn func() (net.Conn, error)
type Proxy interface { type Proxy interface {
@ -63,6 +70,7 @@ type BaseProxy struct {
limiter *rate.Limiter limiter *rate.Limiter
userInfo plugin.UserInfo userInfo plugin.UserInfo
loginMsg *msg.Login loginMsg *msg.Login
pxyConf config.ProxyConf
mu sync.RWMutex mu sync.RWMutex
xl *xlog.Logger xl *xlog.Logger
@ -93,6 +101,10 @@ func (pxy *BaseProxy) GetLoginMsg() *msg.Login {
return pxy.loginMsg return pxy.loginMsg
} }
func (pxy *BaseProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *BaseProxy) Close() { func (pxy *BaseProxy) Close() {
xl := xlog.FromContextSafe(pxy.ctx) xl := xlog.FromContextSafe(pxy.ctx)
xl.Info("proxy closing") xl.Info("proxy closing")
@ -155,10 +167,8 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
return return
} }
// startListenHandler start a goroutine handler for each listener. // startCommonTCPListenersHandler start a goroutine handler for each listener.
// p: p will just be passed to handler(Proxy, utilnet.Conn). func (pxy *BaseProxy) startCommonTCPListenersHandler() {
// handler: each proxy type can set different handler function to deal with connections accepted from listeners.
func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn, config.ServerCommonConf)) {
xl := xlog.FromContextSafe(pxy.ctx) xl := xlog.FromContextSafe(pxy.ctx)
for _, listener := range pxy.listeners { for _, listener := range pxy.listeners {
go func(l net.Listener) { go func(l net.Listener) {
@ -187,12 +197,72 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn,
return return
} }
xl.Info("get a user connection [%s]", c.RemoteAddr().String()) xl.Info("get a user connection [%s]", c.RemoteAddr().String())
go handler(p, c, pxy.serverCfg) go pxy.handleUserTCPConnection(c)
} }
}(listener) }(listener)
} }
} }
// HandleUserTCPConnection is used for incoming user TCP connections.
func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
xl := xlog.FromContextSafe(pxy.Context())
defer userConn.Close()
serverCfg := pxy.serverCfg
cfg := pxy.pxyConf.GetBaseConfig()
// server plugin hook
rc := pxy.GetResourceController()
content := &plugin.NewUserConnContent{
User: pxy.GetUserInfo(),
ProxyName: pxy.GetName(),
ProxyType: cfg.ProxyType,
RemoteAddr: userConn.RemoteAddr().String(),
}
_, err := rc.PluginManager.NewUserConn(content)
if err != nil {
xl.Warn("the user conn [%s] was rejected, err:%v", content.RemoteAddr, err)
return
}
// try all connections from the pool
workConn, err := pxy.GetWorkConnFromPool(userConn.RemoteAddr(), userConn.LocalAddr())
if err != nil {
return
}
defer workConn.Close()
var local io.ReadWriteCloser = workConn
xl.Trace("handler user tcp connection, use_encryption: %t, use_compression: %t", cfg.UseEncryption, cfg.UseCompression)
if cfg.UseEncryption {
local, err = libio.WithEncryption(local, []byte(serverCfg.Token))
if err != nil {
xl.Error("create encryption stream error: %v", err)
return
}
}
if cfg.UseCompression {
local = libio.WithCompression(local)
}
if pxy.GetLimiter() != nil {
local = libio.WrapReadWriteCloser(limit.NewReader(local, pxy.GetLimiter()), limit.NewWriter(local, pxy.GetLimiter()), func() error {
return local.Close()
})
}
xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
name := pxy.GetName()
proxyType := cfg.ProxyType
metrics.Server.OpenConnection(name, proxyType)
inCount, outCount, _ := libio.Join(local, userConn)
metrics.Server.CloseConnection(name, proxyType)
metrics.Server.AddTrafficIn(name, proxyType, inCount)
metrics.Server.AddTrafficOut(name, proxyType, outCount)
xl.Debug("join connections closed")
}
func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int, func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int,
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, loginMsg *msg.Login, getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, loginMsg *msg.Login,
) (pxy Proxy, err error) { ) (pxy Proxy, err error) {
@ -216,114 +286,18 @@ func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.Reso
ctx: xlog.NewContext(ctx, xl), ctx: xlog.NewContext(ctx, xl),
userInfo: userInfo, userInfo: userInfo,
loginMsg: loginMsg, loginMsg: loginMsg,
pxyConf: pxyConf,
} }
switch cfg := pxyConf.(type) {
case *config.TCPProxyConf: factory := proxyFactoryRegistry[reflect.TypeOf(pxyConf)]
basePxy.usedPortsNum = 1 if factory == nil {
pxy = &TCPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.TCPMuxProxyConf:
pxy = &TCPMuxProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.HTTPProxyConf:
pxy = &HTTPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.HTTPSProxyConf:
pxy = &HTTPSProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.UDPProxyConf:
basePxy.usedPortsNum = 1
pxy = &UDPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.STCPProxyConf:
pxy = &STCPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.XTCPProxyConf:
pxy = &XTCPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
case *config.SUDPProxyConf:
pxy = &SUDPProxy{
BaseProxy: &basePxy,
cfg: cfg,
}
default:
return pxy, fmt.Errorf("proxy type not support") return pxy, fmt.Errorf("proxy type not support")
} }
return pxy = factory(&basePxy, pxyConf)
} if pxy == nil {
return nil, fmt.Errorf("proxy not created")
// HandleUserTCPConnection is used for incoming user TCP connections.
// It can be used for tcp, http, https type.
func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.ServerCommonConf) {
xl := xlog.FromContextSafe(pxy.Context())
defer userConn.Close()
// server plugin hook
rc := pxy.GetResourceController()
content := &plugin.NewUserConnContent{
User: pxy.GetUserInfo(),
ProxyName: pxy.GetName(),
ProxyType: pxy.GetConf().GetBaseConfig().ProxyType,
RemoteAddr: userConn.RemoteAddr().String(),
} }
_, err := rc.PluginManager.NewUserConn(content) return pxy, nil
if err != nil {
xl.Warn("the user conn [%s] was rejected, err:%v", content.RemoteAddr, err)
return
}
// try all connections from the pool
workConn, err := pxy.GetWorkConnFromPool(userConn.RemoteAddr(), userConn.LocalAddr())
if err != nil {
return
}
defer workConn.Close()
var local io.ReadWriteCloser = workConn
cfg := pxy.GetConf().GetBaseConfig()
xl.Trace("handler user tcp connection, use_encryption: %t, use_compression: %t", cfg.UseEncryption, cfg.UseCompression)
if cfg.UseEncryption {
local, err = libio.WithEncryption(local, []byte(serverCfg.Token))
if err != nil {
xl.Error("create encryption stream error: %v", err)
return
}
}
if cfg.UseCompression {
local = libio.WithCompression(local)
}
if pxy.GetLimiter() != nil {
local = libio.WrapReadWriteCloser(limit.NewReader(local, pxy.GetLimiter()), limit.NewWriter(local, pxy.GetLimiter()), func() error {
return local.Close()
})
}
xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
name := pxy.GetName()
proxyType := pxy.GetConf().GetBaseConfig().ProxyType
metrics.Server.OpenConnection(name, proxyType)
inCount, outCount, _ := libio.Join(local, userConn)
metrics.Server.CloseConnection(name, proxyType)
metrics.Server.AddTrafficIn(name, proxyType, inCount)
metrics.Server.AddTrafficOut(name, proxyType, outCount)
xl.Debug("join connections closed")
} }
type Manager struct { type Manager struct {

View File

@ -15,16 +15,31 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate" "reflect"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.STCPProxyConf{}), NewSTCPProxy)
}
type STCPProxy struct { type STCPProxy struct {
*BaseProxy *BaseProxy
cfg *config.STCPProxyConf cfg *config.STCPProxyConf
} }
func NewSTCPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.STCPProxyConf)
if !ok {
return nil
}
return &STCPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *STCPProxy) Run() (remoteAddr string, err error) { func (pxy *STCPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
allowUsers := pxy.cfg.AllowUsers allowUsers := pxy.cfg.AllowUsers
@ -40,7 +55,7 @@ func (pxy *STCPProxy) Run() (remoteAddr string, err error) {
pxy.listeners = append(pxy.listeners, listener) pxy.listeners = append(pxy.listeners, listener)
xl.Info("stcp proxy custom listen success") xl.Info("stcp proxy custom listen success")
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startCommonTCPListenersHandler()
return return
} }
@ -48,10 +63,6 @@ func (pxy *STCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *STCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *STCPProxy) Close() { func (pxy *STCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@ -15,16 +15,31 @@
package proxy package proxy
import ( import (
"golang.org/x/time/rate" "reflect"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.SUDPProxyConf{}), NewSUDPProxy)
}
type SUDPProxy struct { type SUDPProxy struct {
*BaseProxy *BaseProxy
cfg *config.SUDPProxyConf cfg *config.SUDPProxyConf
} }
func NewSUDPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.SUDPProxyConf)
if !ok {
return nil
}
return &SUDPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *SUDPProxy) Run() (remoteAddr string, err error) { func (pxy *SUDPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
allowUsers := pxy.cfg.AllowUsers allowUsers := pxy.cfg.AllowUsers
@ -40,7 +55,7 @@ func (pxy *SUDPProxy) Run() (remoteAddr string, err error) {
pxy.listeners = append(pxy.listeners, listener) pxy.listeners = append(pxy.listeners, listener)
xl.Info("sudp proxy custom listen success") xl.Info("sudp proxy custom listen success")
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startCommonTCPListenersHandler()
return return
} }
@ -48,10 +63,6 @@ func (pxy *SUDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *SUDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *SUDPProxy) Close() { func (pxy *SUDPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.VisitorManager.CloseListener(pxy.GetName()) pxy.rc.VisitorManager.CloseListener(pxy.GetName())

View File

@ -17,24 +17,39 @@ package proxy
import ( import (
"fmt" "fmt"
"net" "net"
"reflect"
"strconv" "strconv"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.TCPProxyConf{}), NewTCPProxy)
}
type TCPProxy struct { type TCPProxy struct {
*BaseProxy *BaseProxy
cfg *config.TCPProxyConf cfg *config.TCPProxyConf
realPort int realBindPort int
}
func NewTCPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.TCPProxyConf)
if !ok {
return nil
}
baseProxy.usedPortsNum = 1
return &TCPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
} }
func (pxy *TCPProxy) Run() (remoteAddr string, err error) { func (pxy *TCPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
if pxy.cfg.Group != "" { if pxy.cfg.Group != "" {
l, realPort, errRet := pxy.rc.TCPGroupCtl.Listen(pxy.name, pxy.cfg.Group, pxy.cfg.GroupKey, pxy.serverCfg.ProxyBindAddr, pxy.cfg.RemotePort) l, realBindPort, errRet := pxy.rc.TCPGroupCtl.Listen(pxy.name, pxy.cfg.Group, pxy.cfg.GroupKey, pxy.serverCfg.ProxyBindAddr, pxy.cfg.RemotePort)
if errRet != nil { if errRet != nil {
err = errRet err = errRet
return return
@ -44,20 +59,20 @@ func (pxy *TCPProxy) Run() (remoteAddr string, err error) {
l.Close() l.Close()
} }
}() }()
pxy.realPort = realPort pxy.realBindPort = realBindPort
pxy.listeners = append(pxy.listeners, l) pxy.listeners = append(pxy.listeners, l)
xl.Info("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.Group) xl.Info("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.Group)
} else { } else {
pxy.realPort, err = pxy.rc.TCPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort) pxy.realBindPort, err = pxy.rc.TCPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
if err != nil { if err != nil {
return return
} }
defer func() { defer func() {
if err != nil { if err != nil {
pxy.rc.TCPPortManager.Release(pxy.realPort) pxy.rc.TCPPortManager.Release(pxy.realBindPort)
} }
}() }()
listener, errRet := net.Listen("tcp", net.JoinHostPort(pxy.serverCfg.ProxyBindAddr, strconv.Itoa(pxy.realPort))) listener, errRet := net.Listen("tcp", net.JoinHostPort(pxy.serverCfg.ProxyBindAddr, strconv.Itoa(pxy.realBindPort)))
if errRet != nil { if errRet != nil {
err = errRet err = errRet
return return
@ -66,9 +81,9 @@ func (pxy *TCPProxy) Run() (remoteAddr string, err error) {
xl.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort) xl.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort)
} }
pxy.cfg.RemotePort = pxy.realPort pxy.cfg.RemotePort = pxy.realBindPort
remoteAddr = fmt.Sprintf(":%d", pxy.realPort) remoteAddr = fmt.Sprintf(":%d", pxy.realBindPort)
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startCommonTCPListenersHandler()
return return
} }
@ -76,13 +91,9 @@ func (pxy *TCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPProxy) Close() { func (pxy *TCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
if pxy.cfg.Group == "" { if pxy.cfg.Group == "" {
pxy.rc.TCPPortManager.Release(pxy.realPort) pxy.rc.TCPPortManager.Release(pxy.realBindPort)
} }
} }

View File

@ -17,21 +17,35 @@ package proxy
import ( import (
"fmt" "fmt"
"net" "net"
"reflect"
"strings" "strings"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.TCPMuxProxyConf{}), NewTCPMuxProxy)
}
type TCPMuxProxy struct { type TCPMuxProxy struct {
*BaseProxy *BaseProxy
cfg *config.TCPMuxProxyConf cfg *config.TCPMuxProxyConf
} }
func NewTCPMuxProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.TCPMuxProxyConf)
if !ok {
return nil
}
return &TCPMuxProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *TCPMuxProxy) httpConnectListen( func (pxy *TCPMuxProxy) httpConnectListen(
domain, routeByHTTPUser, httpUser, httpPwd string, addrs []string) ([]string, error, domain, routeByHTTPUser, httpUser, httpPwd string, addrs []string) ([]string, error,
) { ) {
@ -78,7 +92,7 @@ func (pxy *TCPMuxProxy) httpConnectRun() (remoteAddr string, err error) {
} }
} }
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startCommonTCPListenersHandler()
remoteAddr = strings.Join(addrs, ",") remoteAddr = strings.Join(addrs, ",")
return remoteAddr, err return remoteAddr, err
} }
@ -101,10 +115,6 @@ func (pxy *TCPMuxProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *TCPMuxProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *TCPMuxProxy) Close() { func (pxy *TCPMuxProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
} }

View File

@ -19,12 +19,12 @@ import (
"fmt" "fmt"
"io" "io"
"net" "net"
"reflect"
"strconv" "strconv"
"time" "time"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
libio "github.com/fatedier/golib/io" libio "github.com/fatedier/golib/io"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
@ -34,11 +34,15 @@ import (
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.UDPProxyConf{}), NewUDPProxy)
}
type UDPProxy struct { type UDPProxy struct {
*BaseProxy *BaseProxy
cfg *config.UDPProxyConf cfg *config.UDPProxyConf
realPort int realBindPort int
// udpConn is the listener of udp packages // udpConn is the listener of udp packages
udpConn *net.UDPConn udpConn *net.UDPConn
@ -59,21 +63,33 @@ type UDPProxy struct {
isClosed bool isClosed bool
} }
func NewUDPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.UDPProxyConf)
if !ok {
return nil
}
baseProxy.usedPortsNum = 1
return &UDPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *UDPProxy) Run() (remoteAddr string, err error) { func (pxy *UDPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
pxy.realPort, err = pxy.rc.UDPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort) pxy.realBindPort, err = pxy.rc.UDPPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
if err != nil { if err != nil {
return "", fmt.Errorf("acquire port %d error: %v", pxy.cfg.RemotePort, err) return "", fmt.Errorf("acquire port %d error: %v", pxy.cfg.RemotePort, err)
} }
defer func() { defer func() {
if err != nil { if err != nil {
pxy.rc.UDPPortManager.Release(pxy.realPort) pxy.rc.UDPPortManager.Release(pxy.realBindPort)
} }
}() }()
remoteAddr = fmt.Sprintf(":%d", pxy.realPort) remoteAddr = fmt.Sprintf(":%d", pxy.realBindPort)
pxy.cfg.RemotePort = pxy.realPort pxy.cfg.RemotePort = pxy.realBindPort
addr, errRet := net.ResolveUDPAddr("udp", net.JoinHostPort(pxy.serverCfg.ProxyBindAddr, strconv.Itoa(pxy.realPort))) addr, errRet := net.ResolveUDPAddr("udp", net.JoinHostPort(pxy.serverCfg.ProxyBindAddr, strconv.Itoa(pxy.realBindPort)))
if errRet != nil { if errRet != nil {
err = errRet err = errRet
return return
@ -233,10 +249,6 @@ func (pxy *UDPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *UDPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *UDPProxy) Close() { func (pxy *UDPProxy) Close() {
pxy.mu.Lock() pxy.mu.Lock()
defer pxy.mu.Unlock() defer pxy.mu.Unlock()
@ -254,5 +266,5 @@ func (pxy *UDPProxy) Close() {
close(pxy.readCh) close(pxy.readCh)
close(pxy.sendCh) close(pxy.sendCh)
} }
pxy.rc.UDPPortManager.Release(pxy.realPort) pxy.rc.UDPPortManager.Release(pxy.realBindPort)
} }

View File

@ -16,14 +16,18 @@ package proxy
import ( import (
"fmt" "fmt"
"reflect"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
"golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
) )
func init() {
RegisterProxyFactory(reflect.TypeOf(&config.XTCPProxyConf{}), NewXTCPProxy)
}
type XTCPProxy struct { type XTCPProxy struct {
*BaseProxy *BaseProxy
cfg *config.XTCPProxyConf cfg *config.XTCPProxyConf
@ -31,6 +35,17 @@ type XTCPProxy struct {
closeCh chan struct{} closeCh chan struct{}
} }
func NewXTCPProxy(baseProxy *BaseProxy, cfg config.ProxyConf) Proxy {
unwrapped, ok := cfg.(*config.XTCPProxyConf)
if !ok {
return nil
}
return &XTCPProxy{
BaseProxy: baseProxy,
cfg: unwrapped,
}
}
func (pxy *XTCPProxy) Run() (remoteAddr string, err error) { func (pxy *XTCPProxy) Run() (remoteAddr string, err error) {
xl := pxy.xl xl := pxy.xl
@ -72,10 +87,6 @@ func (pxy *XTCPProxy) GetConf() config.ProxyConf {
return pxy.cfg return pxy.cfg
} }
func (pxy *XTCPProxy) GetLimiter() *rate.Limiter {
return pxy.limiter
}
func (pxy *XTCPProxy) Close() { func (pxy *XTCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.NatHoleController.CloseClient(pxy.GetName()) pxy.rc.NatHoleController.CloseClient(pxy.GetName())