|
@@ -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.
|
|
|
|
-// p: p will just be passed to handler(Proxy, utilnet.Conn).
|
|
|
|
-// 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)) {
|
|
|
|
|
|
+// startCommonTCPListenersHandler start a goroutine handler for each listener.
|
|
|
|
+func (pxy *BaseProxy) startCommonTCPListenersHandler() {
|
|
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,97 +197,25 @@ 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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int,
|
|
|
|
- getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, loginMsg *msg.Login,
|
|
|
|
-) (pxy Proxy, err error) {
|
|
|
|
- xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseConfig().ProxyName)
|
|
|
|
-
|
|
|
|
- var limiter *rate.Limiter
|
|
|
|
- limitBytes := pxyConf.GetBaseConfig().BandwidthLimit.Bytes()
|
|
|
|
- if limitBytes > 0 && pxyConf.GetBaseConfig().BandwidthLimitMode == config.BandwidthLimitModeServer {
|
|
|
|
- limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- basePxy := BaseProxy{
|
|
|
|
- name: pxyConf.GetBaseConfig().ProxyName,
|
|
|
|
- rc: rc,
|
|
|
|
- listeners: make([]net.Listener, 0),
|
|
|
|
- poolCount: poolCount,
|
|
|
|
- getWorkConnFn: getWorkConnFn,
|
|
|
|
- serverCfg: serverCfg,
|
|
|
|
- limiter: limiter,
|
|
|
|
- xl: xl,
|
|
|
|
- ctx: xlog.NewContext(ctx, xl),
|
|
|
|
- userInfo: userInfo,
|
|
|
|
- loginMsg: loginMsg,
|
|
|
|
- }
|
|
|
|
- switch cfg := pxyConf.(type) {
|
|
|
|
- case *config.TCPProxyConf:
|
|
|
|
- basePxy.usedPortsNum = 1
|
|
|
|
- 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
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// HandleUserTCPConnection is used for incoming user TCP connections.
|
|
// 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) {
|
|
|
|
|
|
+func (pxy *BaseProxy) handleUserTCPConnection(userConn net.Conn) {
|
|
xl := xlog.FromContextSafe(pxy.Context())
|
|
xl := xlog.FromContextSafe(pxy.Context())
|
|
defer userConn.Close()
|
|
defer userConn.Close()
|
|
|
|
|
|
|
|
+ serverCfg := pxy.serverCfg
|
|
|
|
+ cfg := pxy.pxyConf.GetBaseConfig()
|
|
// server plugin hook
|
|
// server plugin hook
|
|
rc := pxy.GetResourceController()
|
|
rc := pxy.GetResourceController()
|
|
content := &plugin.NewUserConnContent{
|
|
content := &plugin.NewUserConnContent{
|
|
User: pxy.GetUserInfo(),
|
|
User: pxy.GetUserInfo(),
|
|
ProxyName: pxy.GetName(),
|
|
ProxyName: pxy.GetName(),
|
|
- ProxyType: pxy.GetConf().GetBaseConfig().ProxyType,
|
|
|
|
|
|
+ ProxyType: cfg.ProxyType,
|
|
RemoteAddr: userConn.RemoteAddr().String(),
|
|
RemoteAddr: userConn.RemoteAddr().String(),
|
|
}
|
|
}
|
|
_, err := rc.PluginManager.NewUserConn(content)
|
|
_, err := rc.PluginManager.NewUserConn(content)
|
|
@@ -294,7 +232,6 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv
|
|
defer workConn.Close()
|
|
defer workConn.Close()
|
|
|
|
|
|
var local io.ReadWriteCloser = workConn
|
|
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)
|
|
xl.Trace("handler user tcp connection, use_encryption: %t, use_compression: %t", cfg.UseEncryption, cfg.UseCompression)
|
|
if cfg.UseEncryption {
|
|
if cfg.UseEncryption {
|
|
local, err = libio.WithEncryption(local, []byte(serverCfg.Token))
|
|
local, err = libio.WithEncryption(local, []byte(serverCfg.Token))
|
|
@@ -317,7 +254,7 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv
|
|
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
|
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
|
|
|
|
|
name := pxy.GetName()
|
|
name := pxy.GetName()
|
|
- proxyType := pxy.GetConf().GetBaseConfig().ProxyType
|
|
|
|
|
|
+ proxyType := cfg.ProxyType
|
|
metrics.Server.OpenConnection(name, proxyType)
|
|
metrics.Server.OpenConnection(name, proxyType)
|
|
inCount, outCount, _ := libio.Join(local, userConn)
|
|
inCount, outCount, _ := libio.Join(local, userConn)
|
|
metrics.Server.CloseConnection(name, proxyType)
|
|
metrics.Server.CloseConnection(name, proxyType)
|
|
@@ -326,6 +263,43 @@ func HandleUserTCPConnection(pxy Proxy, userConn net.Conn, serverCfg config.Serv
|
|
xl.Debug("join connections closed")
|
|
xl.Debug("join connections closed")
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int,
|
|
|
|
+ getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf, loginMsg *msg.Login,
|
|
|
|
+) (pxy Proxy, err error) {
|
|
|
|
+ xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseConfig().ProxyName)
|
|
|
|
+
|
|
|
|
+ var limiter *rate.Limiter
|
|
|
|
+ limitBytes := pxyConf.GetBaseConfig().BandwidthLimit.Bytes()
|
|
|
|
+ if limitBytes > 0 && pxyConf.GetBaseConfig().BandwidthLimitMode == config.BandwidthLimitModeServer {
|
|
|
|
+ limiter = rate.NewLimiter(rate.Limit(float64(limitBytes)), int(limitBytes))
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ basePxy := BaseProxy{
|
|
|
|
+ name: pxyConf.GetBaseConfig().ProxyName,
|
|
|
|
+ rc: rc,
|
|
|
|
+ listeners: make([]net.Listener, 0),
|
|
|
|
+ poolCount: poolCount,
|
|
|
|
+ getWorkConnFn: getWorkConnFn,
|
|
|
|
+ serverCfg: serverCfg,
|
|
|
|
+ limiter: limiter,
|
|
|
|
+ xl: xl,
|
|
|
|
+ ctx: xlog.NewContext(ctx, xl),
|
|
|
|
+ userInfo: userInfo,
|
|
|
|
+ loginMsg: loginMsg,
|
|
|
|
+ pxyConf: pxyConf,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ factory := proxyFactoryRegistry[reflect.TypeOf(pxyConf)]
|
|
|
|
+ if factory == nil {
|
|
|
|
+ return pxy, fmt.Errorf("proxy type not support")
|
|
|
|
+ }
|
|
|
|
+ pxy = factory(&basePxy, pxyConf)
|
|
|
|
+ if pxy == nil {
|
|
|
|
+ return nil, fmt.Errorf("proxy not created")
|
|
|
|
+ }
|
|
|
|
+ return pxy, nil
|
|
|
|
+}
|
|
|
|
+
|
|
type Manager struct {
|
|
type Manager struct {
|
|
// proxies indexed by proxy name
|
|
// proxies indexed by proxy name
|
|
pxys map[string]Proxy
|
|
pxys map[string]Proxy
|