mirror of https://github.com/fatedier/frp
support wss between frpc and frps (#3503)
parent
b146989703
commit
801e8c6742
15
Release.md
15
Release.md
|
@ -1,18 +1,7 @@
|
||||||
## Notes
|
|
||||||
|
|
||||||
**For enhanced security, the default values for `tls_enable` and `disable_custom_tls_first_byte` have been set to true.**
|
|
||||||
|
|
||||||
If you wish to revert to the previous default values, you need to manually set the values of these two parameters to false.
|
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
* Added support for `allow_users` in stcp, sudp, xtcp. By default, only the same user is allowed to access. Use `*` to allow access from any user. The visitor configuration now supports `server_user` to connect to proxies of other users.
|
* frpc supports connecting to frps via the wss protocol by enabling the configuration `protocol = wss`.
|
||||||
* Added fallback support to a specified alternative visitor when xtcp connection fails.
|
|
||||||
|
|
||||||
### Improvements
|
|
||||||
|
|
||||||
* Increased the default value of `MaxStreamWindowSize` for yamux to 6MB, improving traffic forwarding rate in high-latency scenarios.
|
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
* Fixed an issue where having proxies with the same name would cause previously working proxies to become ineffective in `xtcp`.
|
* Fix an issue caused by a bug in yamux that prevents wss from working properly in certain plugins.
|
||||||
|
|
|
@ -135,7 +135,7 @@ func (svr *Service) Run() error {
|
||||||
if svr.cfg.LoginFailExit {
|
if svr.cfg.LoginFailExit {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
util.RandomSleep(10*time.Second, 0.9, 1.1)
|
util.RandomSleep(5*time.Second, 0.9, 1.1)
|
||||||
} else {
|
} else {
|
||||||
// login success
|
// login success
|
||||||
ctl := NewControl(svr.ctx, svr.runID, conn, cm, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.authSetter)
|
ctl := NewControl(svr.ctx, svr.runID, conn, cm, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.authSetter)
|
||||||
|
@ -427,7 +427,11 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
|
||||||
xl := xlog.FromContextSafe(cm.ctx)
|
xl := xlog.FromContextSafe(cm.ctx)
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
var err error
|
var err error
|
||||||
if cm.cfg.TLSEnable {
|
tlsEnable := cm.cfg.TLSEnable
|
||||||
|
if cm.cfg.Protocol == "wss" {
|
||||||
|
tlsEnable = true
|
||||||
|
}
|
||||||
|
if tlsEnable {
|
||||||
sn := cm.cfg.TLSServerName
|
sn := cm.cfg.TLSServerName
|
||||||
if sn == "" {
|
if sn == "" {
|
||||||
sn = cm.cfg.ServerAddr
|
sn = cm.cfg.ServerAddr
|
||||||
|
@ -451,10 +455,23 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
|
||||||
}
|
}
|
||||||
dialOptions := []libdial.DialOption{}
|
dialOptions := []libdial.DialOption{}
|
||||||
protocol := cm.cfg.Protocol
|
protocol := cm.cfg.Protocol
|
||||||
if protocol == "websocket" {
|
switch protocol {
|
||||||
|
case "websocket":
|
||||||
protocol = "tcp"
|
protocol = "tcp"
|
||||||
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket()}))
|
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, "")}))
|
||||||
|
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
|
||||||
|
Hook: utilnet.DialHookCustomTLSHeadByte(tlsConfig != nil, cm.cfg.DisableCustomTLSFirstByte),
|
||||||
|
}))
|
||||||
|
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
||||||
|
case "wss":
|
||||||
|
protocol = "tcp"
|
||||||
|
dialOptions = append(dialOptions, libdial.WithTLSConfigAndPriority(100, tlsConfig))
|
||||||
|
// Make sure that if it is wss, the websocket hook is executed after the tls hook.
|
||||||
|
dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
|
||||||
|
default:
|
||||||
|
dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
|
||||||
}
|
}
|
||||||
|
|
||||||
if cm.cfg.ConnectServerLocalIP != "" {
|
if cm.cfg.ConnectServerLocalIP != "" {
|
||||||
dialOptions = append(dialOptions, libdial.WithLocalAddr(cm.cfg.ConnectServerLocalIP))
|
dialOptions = append(dialOptions, libdial.WithLocalAddr(cm.cfg.ConnectServerLocalIP))
|
||||||
}
|
}
|
||||||
|
@ -464,10 +481,6 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
|
||||||
libdial.WithKeepAlive(time.Duration(cm.cfg.DialServerKeepAlive)*time.Second),
|
libdial.WithKeepAlive(time.Duration(cm.cfg.DialServerKeepAlive)*time.Second),
|
||||||
libdial.WithProxy(proxyType, addr),
|
libdial.WithProxy(proxyType, addr),
|
||||||
libdial.WithProxyAuth(auth),
|
libdial.WithProxyAuth(auth),
|
||||||
libdial.WithTLSConfig(tlsConfig),
|
|
||||||
libdial.WithAfterHook(libdial.AfterHook{
|
|
||||||
Hook: utilnet.DialHookCustomTLSHeadByte(tlsConfig != nil, cm.cfg.DisableCustomTLSFirstByte),
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
conn, err := libdial.DialContext(
|
conn, err := libdial.DialContext(
|
||||||
cm.ctx,
|
cm.ctx,
|
||||||
|
|
|
@ -77,6 +77,7 @@ var (
|
||||||
bindPort int
|
bindPort int
|
||||||
|
|
||||||
tlsEnable bool
|
tlsEnable bool
|
||||||
|
tlsServerName string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -88,13 +89,14 @@ func init() {
|
||||||
func RegisterCommonFlags(cmd *cobra.Command) {
|
func RegisterCommonFlags(cmd *cobra.Command) {
|
||||||
cmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
cmd.PersistentFlags().StringVarP(&serverAddr, "server_addr", "s", "127.0.0.1:7000", "frp server's address")
|
||||||
cmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
cmd.PersistentFlags().StringVarP(&user, "user", "u", "", "user")
|
||||||
cmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp or kcp or websocket")
|
cmd.PersistentFlags().StringVarP(&protocol, "protocol", "p", "tcp", "tcp, kcp, quic, websocket, wss")
|
||||||
cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
cmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
cmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
cmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
cmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
cmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
cmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
cmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
cmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
cmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
cmd.PersistentFlags().BoolVarP(&tlsEnable, "tls_enable", "", true, "enable frpc tls")
|
cmd.PersistentFlags().BoolVarP(&tlsEnable, "tls_enable", "", true, "enable frpc tls")
|
||||||
|
cmd.PersistentFlags().StringVarP(&tlsServerName, "tls_server_name", "", "", "specify the custom server name of tls certificate")
|
||||||
cmd.PersistentFlags().StringVarP(&dnsServer, "dns_server", "", "", "specify dns server instead of using system default one")
|
cmd.PersistentFlags().StringVarP(&dnsServer, "dns_server", "", "", "specify dns server instead of using system default one")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +188,7 @@ func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
|
||||||
cfg.ClientConfig = auth.GetDefaultClientConf()
|
cfg.ClientConfig = auth.GetDefaultClientConf()
|
||||||
cfg.Token = token
|
cfg.Token = token
|
||||||
cfg.TLSEnable = tlsEnable
|
cfg.TLSEnable = tlsEnable
|
||||||
|
cfg.TLSServerName = tlsServerName
|
||||||
|
|
||||||
cfg.Complete()
|
cfg.Complete()
|
||||||
if err = cfg.Validate(); err != nil {
|
if err = cfg.Validate(); err != nil {
|
||||||
|
|
|
@ -95,7 +95,7 @@ user = your_name
|
||||||
login_fail_exit = true
|
login_fail_exit = true
|
||||||
|
|
||||||
# communication protocol used to connect to server
|
# communication protocol used to connect to server
|
||||||
# supports tcp, kcp, quic and websocket now, default is tcp
|
# supports tcp, kcp, quic, websocket and wss now, default is tcp
|
||||||
protocol = tcp
|
protocol = tcp
|
||||||
|
|
||||||
# set client binding ip when connect server, default is empty.
|
# set client binding ip when connect server, default is empty.
|
||||||
|
|
5
go.mod
5
go.mod
|
@ -6,7 +6,7 @@ require (
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
github.com/coreos/go-oidc/v3 v3.4.0
|
github.com/coreos/go-oidc/v3 v3.4.0
|
||||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb
|
||||||
github.com/fatedier/golib v0.1.1-0.20230320133937-a7edcc8c793d
|
github.com/fatedier/golib v0.1.1-0.20230628070619-a1a0c648236a
|
||||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible
|
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible
|
||||||
github.com/go-playground/validator/v10 v10.11.0
|
github.com/go-playground/validator/v10 v10.11.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
|
@ -75,3 +75,6 @@ require (
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO(fatedier): Temporary use the modified version, update to the official version after merging into the official repository.
|
||||||
|
replace github.com/hashicorp/yamux => github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -121,10 +121,12 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
|
||||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
||||||
github.com/fatedier/golib v0.1.1-0.20230320133937-a7edcc8c793d h1:/m9Atycn9uKRwwOkxv4c+zaugxRgkdSG/Eg3IJWOpNs=
|
github.com/fatedier/golib v0.1.1-0.20230628070619-a1a0c648236a h1:HiRTFdy3ary86Vi2nsoINy2/YgjDPQ+21j3ikwJSD2E=
|
||||||
github.com/fatedier/golib v0.1.1-0.20230320133937-a7edcc8c793d/go.mod h1:Wdn1pJ0dHB1lah6FPYwt4AO9NEmWI0OzW13dpzC9g4E=
|
github.com/fatedier/golib v0.1.1-0.20230628070619-a1a0c648236a/go.mod h1:Wdn1pJ0dHB1lah6FPYwt4AO9NEmWI0OzW13dpzC9g4E=
|
||||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
|
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
|
||||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
|
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
|
||||||
|
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo=
|
||||||
|
github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
@ -270,8 +272,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
|
||||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
|
|
||||||
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
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.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
|
||||||
"github.com/fatedier/frp/pkg/auth"
|
"github.com/fatedier/frp/pkg/auth"
|
||||||
|
@ -117,7 +118,7 @@ type ClientCommonConf struct {
|
||||||
Start []string `ini:"start" json:"start"`
|
Start []string `ini:"start" json:"start"`
|
||||||
// Start map[string]struct{} `json:"start"`
|
// Start map[string]struct{} `json:"start"`
|
||||||
// Protocol specifies the protocol to use when interacting with the server.
|
// Protocol specifies the protocol to use when interacting with the server.
|
||||||
// Valid values are "tcp", "kcp", "quic" and "websocket". By default, this value
|
// Valid values are "tcp", "kcp", "quic", "websocket" and "wss". By default, this value
|
||||||
// is "tcp".
|
// is "tcp".
|
||||||
Protocol string `ini:"protocol" json:"protocol"`
|
Protocol string `ini:"protocol" json:"protocol"`
|
||||||
// QUIC protocol options
|
// QUIC protocol options
|
||||||
|
@ -230,7 +231,7 @@ func (cfg *ClientCommonConf) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Protocol != "tcp" && cfg.Protocol != "kcp" && cfg.Protocol != "websocket" && cfg.Protocol != "quic" {
|
if !lo.Contains([]string{"tcp", "kcp", "quic", "websocket", "wss"}, cfg.Protocol) {
|
||||||
return fmt.Errorf("invalid protocol")
|
return fmt.Errorf("invalid protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,15 @@ func DialHookCustomTLSHeadByte(enableTLS bool, disableCustomTLSHeadByte bool) li
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DialHookWebsocket() libdial.AfterHookFunc {
|
func DialHookWebsocket(protocol string, host string) libdial.AfterHookFunc {
|
||||||
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
return func(ctx context.Context, c net.Conn, addr string) (context.Context, net.Conn, error) {
|
||||||
addr = "ws://" + addr + FrpWebsocketPath
|
if protocol != "wss" {
|
||||||
|
protocol = "ws"
|
||||||
|
}
|
||||||
|
if host == "" {
|
||||||
|
host = addr
|
||||||
|
}
|
||||||
|
addr = protocol + "://" + host + FrpWebsocketPath
|
||||||
uri, err := url.Parse(addr)
|
uri, err := url.Parse(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -331,24 +331,29 @@ var _ = ginkgo.Describe("[Feature: Basic]", func() {
|
||||||
proxyExtraConfig string
|
proxyExtraConfig string
|
||||||
visitorExtraConfig string
|
visitorExtraConfig string
|
||||||
expectError bool
|
expectError bool
|
||||||
user2 bool
|
deployUser2Client bool
|
||||||
|
// skipXTCP is used to skip xtcp test case
|
||||||
|
skipXTCP bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
proxyName: "normal",
|
proxyName: "normal",
|
||||||
bindPortName: port.GenName("Normal"),
|
bindPortName: port.GenName("Normal"),
|
||||||
visitorSK: correctSK,
|
visitorSK: correctSK,
|
||||||
|
skipXTCP: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
proxyName: "with-encryption",
|
proxyName: "with-encryption",
|
||||||
bindPortName: port.GenName("WithEncryption"),
|
bindPortName: port.GenName("WithEncryption"),
|
||||||
visitorSK: correctSK,
|
visitorSK: correctSK,
|
||||||
commonExtraConfig: "use_encryption = true",
|
commonExtraConfig: "use_encryption = true",
|
||||||
|
skipXTCP: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
proxyName: "with-compression",
|
proxyName: "with-compression",
|
||||||
bindPortName: port.GenName("WithCompression"),
|
bindPortName: port.GenName("WithCompression"),
|
||||||
visitorSK: correctSK,
|
visitorSK: correctSK,
|
||||||
commonExtraConfig: "use_compression = true",
|
commonExtraConfig: "use_compression = true",
|
||||||
|
skipXTCP: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
proxyName: "with-encryption-and-compression",
|
proxyName: "with-encryption-and-compression",
|
||||||
|
@ -371,7 +376,7 @@ var _ = ginkgo.Describe("[Feature: Basic]", func() {
|
||||||
visitorSK: correctSK,
|
visitorSK: correctSK,
|
||||||
proxyExtraConfig: "allow_users = another, user2",
|
proxyExtraConfig: "allow_users = another, user2",
|
||||||
visitorExtraConfig: "server_user = user1",
|
visitorExtraConfig: "server_user = user1",
|
||||||
user2: true,
|
deployUser2Client: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
proxyName: "not-allowed-user",
|
proxyName: "not-allowed-user",
|
||||||
|
@ -387,7 +392,7 @@ var _ = ginkgo.Describe("[Feature: Basic]", func() {
|
||||||
visitorSK: correctSK,
|
visitorSK: correctSK,
|
||||||
proxyExtraConfig: "allow_users = *",
|
proxyExtraConfig: "allow_users = *",
|
||||||
visitorExtraConfig: "server_user = user1",
|
visitorExtraConfig: "server_user = user1",
|
||||||
user2: true,
|
deployUser2Client: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +404,7 @@ var _ = ginkgo.Describe("[Feature: Basic]", func() {
|
||||||
config := getProxyVisitorConf(
|
config := getProxyVisitorConf(
|
||||||
test.proxyName, test.bindPortName, test.visitorSK, test.commonExtraConfig+"\n"+test.visitorExtraConfig,
|
test.proxyName, test.bindPortName, test.visitorSK, test.commonExtraConfig+"\n"+test.visitorExtraConfig,
|
||||||
) + "\n"
|
) + "\n"
|
||||||
if test.user2 {
|
if test.deployUser2Client {
|
||||||
clientUser2VisitorConf += config
|
clientUser2VisitorConf += config
|
||||||
} else {
|
} else {
|
||||||
clientVisitorConf += config
|
clientVisitorConf += config
|
||||||
|
@ -411,7 +416,10 @@ var _ = ginkgo.Describe("[Feature: Basic]", func() {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
timeout := time.Second
|
timeout := time.Second
|
||||||
if t == "xtcp" {
|
if t == "xtcp" {
|
||||||
timeout = 4 * time.Second
|
if test.skipXTCP {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
timeout = 10 * time.Second
|
||||||
}
|
}
|
||||||
framework.NewRequestExpect(f).
|
framework.NewRequestExpect(f).
|
||||||
RequestModify(func(r *request.Request) {
|
RequestModify(func(r *request.Request) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package basic
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo/v2"
|
"github.com/onsi/ginkgo/v2"
|
||||||
|
|
||||||
|
@ -15,6 +16,10 @@ import (
|
||||||
type generalTestConfigures struct {
|
type generalTestConfigures struct {
|
||||||
server string
|
server string
|
||||||
client string
|
client string
|
||||||
|
clientPrefix string
|
||||||
|
client2 string
|
||||||
|
client2Prefix string
|
||||||
|
testDelay time.Duration
|
||||||
expectError bool
|
expectError bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +35,9 @@ func renderBindPortConfig(protocol string) string {
|
||||||
func runClientServerTest(f *framework.Framework, configures *generalTestConfigures) {
|
func runClientServerTest(f *framework.Framework, configures *generalTestConfigures) {
|
||||||
serverConf := consts.DefaultServerConfig
|
serverConf := consts.DefaultServerConfig
|
||||||
clientConf := consts.DefaultClientConfig
|
clientConf := consts.DefaultClientConfig
|
||||||
|
if configures.clientPrefix != "" {
|
||||||
|
clientConf = configures.clientPrefix
|
||||||
|
}
|
||||||
|
|
||||||
serverConf += fmt.Sprintf(`
|
serverConf += fmt.Sprintf(`
|
||||||
%s
|
%s
|
||||||
|
@ -54,7 +62,23 @@ func runClientServerTest(f *framework.Framework, configures *generalTestConfigur
|
||||||
framework.UDPEchoServerPort, udpPortName,
|
framework.UDPEchoServerPort, udpPortName,
|
||||||
)
|
)
|
||||||
|
|
||||||
f.RunProcesses([]string{serverConf}, []string{clientConf})
|
clientConfs := []string{clientConf}
|
||||||
|
if configures.client2 != "" {
|
||||||
|
client2Conf := consts.DefaultClientConfig
|
||||||
|
if configures.client2Prefix != "" {
|
||||||
|
client2Conf = configures.client2Prefix
|
||||||
|
}
|
||||||
|
client2Conf += fmt.Sprintf(`
|
||||||
|
%s
|
||||||
|
`, configures.client2)
|
||||||
|
clientConfs = append(clientConfs, client2Conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.RunProcesses([]string{serverConf}, clientConfs)
|
||||||
|
|
||||||
|
if configures.testDelay > 0 {
|
||||||
|
time.Sleep(configures.testDelay)
|
||||||
|
}
|
||||||
|
|
||||||
framework.NewRequestExpect(f).PortName(tcpPortName).ExpectError(configures.expectError).Explain("tcp proxy").Ensure()
|
framework.NewRequestExpect(f).PortName(tcpPortName).ExpectError(configures.expectError).Explain("tcp proxy").Ensure()
|
||||||
framework.NewRequestExpect(f).Protocol("udp").
|
framework.NewRequestExpect(f).Protocol("udp").
|
||||||
|
@ -84,6 +108,33 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// wss is special, it needs to be tested separately.
|
||||||
|
// frps only supports ws, so there should be a proxy to terminate TLS before frps.
|
||||||
|
ginkgo.Describe("Protocol wss", func() {
|
||||||
|
wssPort := f.AllocPort()
|
||||||
|
configures := &generalTestConfigures{
|
||||||
|
clientPrefix: fmt.Sprintf(`
|
||||||
|
[common]
|
||||||
|
server_addr = 127.0.0.1
|
||||||
|
server_port = %d
|
||||||
|
protocol = wss
|
||||||
|
log_level = trace
|
||||||
|
login_fail_exit = false
|
||||||
|
`, wssPort),
|
||||||
|
// Due to the fact that frps cannot directly accept wss connections, we use the https2http plugin of another frpc to terminate TLS.
|
||||||
|
client2: fmt.Sprintf(`
|
||||||
|
[wss2ws]
|
||||||
|
type = tcp
|
||||||
|
remote_port = %d
|
||||||
|
plugin = https2http
|
||||||
|
plugin_local_addr = 127.0.0.1:{{ .%s }}
|
||||||
|
`, wssPort, consts.PortServerName),
|
||||||
|
testDelay: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
defineClientServerTest("wss", f, configures)
|
||||||
|
})
|
||||||
|
|
||||||
ginkgo.Describe("Authentication", func() {
|
ginkgo.Describe("Authentication", func() {
|
||||||
defineClientServerTest("Token Correct", f, &generalTestConfigures{
|
defineClientServerTest("Token Correct", f, &generalTestConfigures{
|
||||||
server: "token = 123456",
|
server: "token = 123456",
|
||||||
|
|
Loading…
Reference in New Issue