mirror of
https://github.com/fatedier/frp.git
synced 2026-08-01 13:22:54 +08:00
Compare commits
2
Commits
c937cb16e4
...
33ab7eedd6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33ab7eedd6 | ||
|
|
2e2802ea13 |
@@ -6,3 +6,7 @@
|
|||||||
## Improvements
|
## Improvements
|
||||||
|
|
||||||
* **VirtualNet**: Implemented intelligent reconnection with exponential backoff. When connection errors occur repeatedly, the reconnect interval increases from 60s to 300s (max), reducing unnecessary reconnection attempts. Normal disconnections still reconnect quickly at 10s intervals.
|
* **VirtualNet**: Implemented intelligent reconnection with exponential backoff. When connection errors occur repeatedly, the reconnect interval increases from 60s to 300s (max), reducing unnecessary reconnection attempts. Normal disconnections still reconnect quickly at 10s intervals.
|
||||||
|
|
||||||
|
## Fixes
|
||||||
|
|
||||||
|
* Fix deadlock issue when TCP connection is closed. Previously, sending messages could block forever if the connection handler had already stopped.
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ func NewControl(ctx context.Context, sessionCtx *SessionContext) (*Control, erro
|
|||||||
ctl.msgDispatcher = msg.NewDispatcher(sessionCtx.Conn)
|
ctl.msgDispatcher = msg.NewDispatcher(sessionCtx.Conn)
|
||||||
}
|
}
|
||||||
ctl.registerMsgHandlers()
|
ctl.registerMsgHandlers()
|
||||||
ctl.msgTransporter = transport.NewMessageTransporter(ctl.msgDispatcher.SendChannel())
|
ctl.msgTransporter = transport.NewMessageTransporter(ctl.msgDispatcher)
|
||||||
|
|
||||||
ctl.pm = proxy.NewManager(ctl.ctx, sessionCtx.Common, ctl.msgTransporter, sessionCtx.VnetController)
|
ctl.pm = proxy.NewManager(ctl.ctx, sessionCtx.Common, ctl.msgTransporter, sessionCtx.VnetController)
|
||||||
ctl.vm = visitor.NewManager(ctl.ctx, sessionCtx.RunID, sessionCtx.Common,
|
ctl.vm = visitor.NewManager(ctl.ctx, sessionCtx.RunID, sessionCtx.Common,
|
||||||
|
|||||||
+3
-2
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/fatedier/frp/pkg/auth"
|
"github.com/fatedier/frp/pkg/auth"
|
||||||
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/policy/security"
|
||||||
httppkg "github.com/fatedier/frp/pkg/util/http"
|
httppkg "github.com/fatedier/frp/pkg/util/http"
|
||||||
"github.com/fatedier/frp/pkg/util/log"
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
netpkg "github.com/fatedier/frp/pkg/util/net"
|
netpkg "github.com/fatedier/frp/pkg/util/net"
|
||||||
@@ -64,7 +65,7 @@ type ServiceOptions struct {
|
|||||||
ProxyCfgs []v1.ProxyConfigurer
|
ProxyCfgs []v1.ProxyConfigurer
|
||||||
VisitorCfgs []v1.VisitorConfigurer
|
VisitorCfgs []v1.VisitorConfigurer
|
||||||
|
|
||||||
UnsafeFeatures v1.UnsafeFeatures
|
UnsafeFeatures *security.UnsafeFeatures
|
||||||
|
|
||||||
// ConfigFilePath is the path to the configuration file used to initialize.
|
// ConfigFilePath is the path to the configuration file used to initialize.
|
||||||
// If it is empty, it means that the configuration file is not used for initialization.
|
// If it is empty, it means that the configuration file is not used for initialization.
|
||||||
@@ -124,7 +125,7 @@ type Service struct {
|
|||||||
visitorCfgs []v1.VisitorConfigurer
|
visitorCfgs []v1.VisitorConfigurer
|
||||||
clientSpec *msg.ClientSpec
|
clientSpec *msg.ClientSpec
|
||||||
|
|
||||||
unsafeFeatures v1.UnsafeFeatures
|
unsafeFeatures *security.UnsafeFeatures
|
||||||
|
|
||||||
// The configuration file used to initialize this client, or an empty
|
// The configuration file used to initialize this client, or an empty
|
||||||
// string if no configuration file was used.
|
// string if no configuration file was used.
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/fatedier/frp/pkg/config"
|
"github.com/fatedier/frp/pkg/config"
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/config/v1/validation"
|
"github.com/fatedier/frp/pkg/config/v1/validation"
|
||||||
|
"github.com/fatedier/frp/pkg/policy/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
var proxyTypes = []v1.ProxyType{
|
var proxyTypes = []v1.ProxyType{
|
||||||
@@ -78,7 +79,7 @@ func NewProxyCommand(name string, c v1.ProxyConfigurer, clientCfg *v1.ClientComm
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
|
unsafeFeatures := security.NewUnsafeFeatures(allowUnsafe)
|
||||||
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
|
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
@@ -108,7 +109,7 @@ func NewVisitorCommand(name string, c v1.VisitorConfigurer, clientCfg *v1.Client
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
|
unsafeFeatures := security.NewUnsafeFeatures(allowUnsafe)
|
||||||
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
|
if _, err := validation.ValidateClientCommonConfig(clientCfg, unsafeFeatures); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|||||||
+10
-6
@@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -31,7 +32,8 @@ import (
|
|||||||
"github.com/fatedier/frp/pkg/config"
|
"github.com/fatedier/frp/pkg/config"
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/config/v1/validation"
|
"github.com/fatedier/frp/pkg/config/v1/validation"
|
||||||
"github.com/fatedier/frp/pkg/featuregate"
|
"github.com/fatedier/frp/pkg/policy/featuregate"
|
||||||
|
"github.com/fatedier/frp/pkg/policy/security"
|
||||||
"github.com/fatedier/frp/pkg/util/log"
|
"github.com/fatedier/frp/pkg/util/log"
|
||||||
"github.com/fatedier/frp/pkg/util/version"
|
"github.com/fatedier/frp/pkg/util/version"
|
||||||
)
|
)
|
||||||
@@ -49,7 +51,9 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
|
rootCmd.PersistentFlags().StringVarP(&cfgDir, "config_dir", "", "", "config directory, run one frpc service for each file in config directory")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
|
rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frpc")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
|
rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause an errors")
|
||||||
rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow-unsafe", "", []string{}, "allowed unsafe features, one or more of: TokenSourceExec")
|
|
||||||
|
rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow-unsafe", "", []string{},
|
||||||
|
fmt.Sprintf("allowed unsafe features, one or more of: %s", strings.Join(security.ClientUnsafeFeatures, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
@@ -61,7 +65,7 @@ var rootCmd = &cobra.Command{
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
|
unsafeFeatures := security.NewUnsafeFeatures(allowUnsafe)
|
||||||
|
|
||||||
// If cfgDir is not empty, run multiple frpc service for each config file in cfgDir.
|
// If cfgDir is not empty, run multiple frpc service for each config file in cfgDir.
|
||||||
// Note that it's only designed for testing. It's not guaranteed to be stable.
|
// Note that it's only designed for testing. It's not guaranteed to be stable.
|
||||||
@@ -80,7 +84,7 @@ var rootCmd = &cobra.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func runMultipleClients(cfgDir string, unsafeFeatures v1.UnsafeFeatures) error {
|
func runMultipleClients(cfgDir string, unsafeFeatures *security.UnsafeFeatures) error {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
err := filepath.WalkDir(cfgDir, func(path string, d fs.DirEntry, err error) error {
|
err := filepath.WalkDir(cfgDir, func(path string, d fs.DirEntry, err error) error {
|
||||||
if err != nil || d.IsDir() {
|
if err != nil || d.IsDir() {
|
||||||
@@ -115,7 +119,7 @@ func handleTermSignal(svr *client.Service) {
|
|||||||
svr.GracefulClose(500 * time.Millisecond)
|
svr.GracefulClose(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runClient(cfgFilePath string, unsafeFeatures v1.UnsafeFeatures) error {
|
func runClient(cfgFilePath string, unsafeFeatures *security.UnsafeFeatures) error {
|
||||||
cfg, proxyCfgs, visitorCfgs, isLegacyFormat, err := config.LoadClientConfig(cfgFilePath, strictConfigMode)
|
cfg, proxyCfgs, visitorCfgs, isLegacyFormat, err := config.LoadClientConfig(cfgFilePath, strictConfigMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -145,7 +149,7 @@ func startService(
|
|||||||
cfg *v1.ClientCommonConfig,
|
cfg *v1.ClientCommonConfig,
|
||||||
proxyCfgs []v1.ProxyConfigurer,
|
proxyCfgs []v1.ProxyConfigurer,
|
||||||
visitorCfgs []v1.VisitorConfigurer,
|
visitorCfgs []v1.VisitorConfigurer,
|
||||||
unsafeFeatures v1.UnsafeFeatures,
|
unsafeFeatures *security.UnsafeFeatures,
|
||||||
cfgFile string,
|
cfgFile string,
|
||||||
) error {
|
) error {
|
||||||
log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
|
log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor)
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/fatedier/frp/pkg/config"
|
"github.com/fatedier/frp/pkg/config"
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
|
||||||
"github.com/fatedier/frp/pkg/config/v1/validation"
|
"github.com/fatedier/frp/pkg/config/v1/validation"
|
||||||
|
"github.com/fatedier/frp/pkg/policy/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -43,7 +43,7 @@ var verifyCmd = &cobra.Command{
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
unsafeFeatures := v1.NewUnsafeFeatures(allowUnsafe)
|
unsafeFeatures := security.NewUnsafeFeatures(allowUnsafe)
|
||||||
warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs, unsafeFeatures)
|
warning, err := validation.ValidateAllClientConfig(cliCfg, proxyCfgs, visitorCfgs, unsafeFeatures)
|
||||||
if warning != nil {
|
if warning != nil {
|
||||||
fmt.Printf("WARNING: %v\n", warning)
|
fmt.Printf("WARNING: %v\n", warning)
|
||||||
|
|||||||
@@ -248,23 +248,3 @@ type AuthOIDCClientConfig struct {
|
|||||||
type VirtualNetConfig struct {
|
type VirtualNetConfig struct {
|
||||||
Address string `json:"address,omitempty"`
|
Address string `json:"address,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
UnsafeFeatureTokenSourceExec = "TokenSourceExec"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UnsafeFeatures struct {
|
|
||||||
features map[string]bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewUnsafeFeatures(allowed []string) UnsafeFeatures {
|
|
||||||
features := make(map[string]bool)
|
|
||||||
for _, f := range allowed {
|
|
||||||
features[f] = true
|
|
||||||
}
|
|
||||||
return UnsafeFeatures{features: features}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u UnsafeFeatures) IsEnabled(feature string) bool {
|
|
||||||
return u.features[feature]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -23,70 +23,111 @@ import (
|
|||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
|
|
||||||
v1 "github.com/fatedier/frp/pkg/config/v1"
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
"github.com/fatedier/frp/pkg/featuregate"
|
"github.com/fatedier/frp/pkg/policy/featuregate"
|
||||||
|
"github.com/fatedier/frp/pkg/policy/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.UnsafeFeatures) (Warning, error) {
|
func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures *security.UnsafeFeatures) (Warning, error) {
|
||||||
var (
|
var (
|
||||||
warnings Warning
|
warnings Warning
|
||||||
errs error
|
errs error
|
||||||
)
|
)
|
||||||
// validate feature gates
|
|
||||||
if c.VirtualNet.Address != "" {
|
validators := []func() (Warning, error){
|
||||||
if !featuregate.Enabled(featuregate.VirtualNet) {
|
func() (Warning, error) { return validateFeatureGates(c) },
|
||||||
return warnings, fmt.Errorf("VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag")
|
func() (Warning, error) { return validateAuthConfig(&c.Auth, unsafeFeatures) },
|
||||||
}
|
func() (Warning, error) { return nil, validateLogConfig(&c.Log) },
|
||||||
|
func() (Warning, error) { return nil, validateWebServerConfig(&c.WebServer) },
|
||||||
|
func() (Warning, error) { return validateTransportConfig(&c.Transport) },
|
||||||
|
func() (Warning, error) { return validateIncludeFiles(c.IncludeConfigFiles) },
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(SupportedAuthMethods, c.Auth.Method) {
|
for _, v := range validators {
|
||||||
|
w, err := v()
|
||||||
|
warnings = AppendError(warnings, w)
|
||||||
|
errs = AppendError(errs, err)
|
||||||
|
}
|
||||||
|
return warnings, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateFeatureGates(c *v1.ClientCommonConfig) (Warning, error) {
|
||||||
|
if c.VirtualNet.Address != "" {
|
||||||
|
if !featuregate.Enabled(featuregate.VirtualNet) {
|
||||||
|
return nil, fmt.Errorf("VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateAuthConfig(c *v1.AuthClientConfig, unsafeFeatures *security.UnsafeFeatures) (Warning, error) {
|
||||||
|
var errs error
|
||||||
|
if !slices.Contains(SupportedAuthMethods, c.Method) {
|
||||||
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
|
errs = AppendError(errs, fmt.Errorf("invalid auth method, optional values are %v", SupportedAuthMethods))
|
||||||
}
|
}
|
||||||
if !lo.Every(SupportedAuthAdditionalScopes, c.Auth.AdditionalScopes) {
|
if !lo.Every(SupportedAuthAdditionalScopes, c.AdditionalScopes) {
|
||||||
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", SupportedAuthAdditionalScopes))
|
errs = AppendError(errs, fmt.Errorf("invalid auth additional scopes, optional values are %v", SupportedAuthAdditionalScopes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate token/tokenSource mutual exclusivity
|
// Validate token/tokenSource mutual exclusivity
|
||||||
if c.Auth.Token != "" && c.Auth.TokenSource != nil {
|
if c.Token != "" && c.TokenSource != nil {
|
||||||
errs = AppendError(errs, fmt.Errorf("cannot specify both auth.token and auth.tokenSource"))
|
errs = AppendError(errs, fmt.Errorf("cannot specify both auth.token and auth.tokenSource"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate tokenSource if specified
|
// Validate tokenSource if specified
|
||||||
if c.Auth.TokenSource != nil {
|
if c.TokenSource != nil {
|
||||||
if c.Auth.TokenSource.Type == "exec" && !unsafeFeatures.IsEnabled(v1.UnsafeFeatureTokenSourceExec) {
|
if c.TokenSource.Type == "exec" {
|
||||||
errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.tokenSource.type"))
|
if !unsafeFeatures.IsEnabled(security.TokenSourceExec) {
|
||||||
|
errs = AppendError(errs, fmt.Errorf("unsafe feature %q is not enabled. "+
|
||||||
|
"To enable it, start frpc with '--allow-unsafe %s'", security.TokenSourceExec, security.TokenSourceExec))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err := c.Auth.TokenSource.Validate(); err != nil {
|
if err := c.TokenSource.Validate(); err != nil {
|
||||||
errs = AppendError(errs, fmt.Errorf("invalid auth.tokenSource: %v", err))
|
errs = AppendError(errs, fmt.Errorf("invalid auth.tokenSource: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Auth.OIDC.TokenSource != nil {
|
if err := validateOIDCConfig(&c.OIDC, unsafeFeatures); err != nil {
|
||||||
// Validate oidc.tokenSource mutual exclusivity with other fields of oidc
|
|
||||||
if c.Auth.OIDC.ClientID != "" || c.Auth.OIDC.ClientSecret != "" || c.Auth.OIDC.Audience != "" ||
|
|
||||||
c.Auth.OIDC.Scope != "" || c.Auth.OIDC.TokenEndpointURL != "" || len(c.Auth.OIDC.AdditionalEndpointParams) > 0 ||
|
|
||||||
c.Auth.OIDC.TrustedCaFile != "" || c.Auth.OIDC.InsecureSkipVerify || c.Auth.OIDC.ProxyURL != "" {
|
|
||||||
errs = AppendError(errs, fmt.Errorf("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc"))
|
|
||||||
}
|
|
||||||
if c.Auth.OIDC.TokenSource.Type == "exec" && !unsafeFeatures.IsEnabled(v1.UnsafeFeatureTokenSourceExec) {
|
|
||||||
errs = AppendError(errs, fmt.Errorf("unsafe 'exec' not allowed for auth.oidc.tokenSource.type"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateLogConfig(&c.Log); err != nil {
|
|
||||||
errs = AppendError(errs, err)
|
errs = AppendError(errs, err)
|
||||||
}
|
}
|
||||||
|
return nil, errs
|
||||||
|
}
|
||||||
|
|
||||||
if err := validateWebServerConfig(&c.WebServer); err != nil {
|
func validateOIDCConfig(c *v1.AuthOIDCClientConfig, unsafeFeatures *security.UnsafeFeatures) error {
|
||||||
errs = AppendError(errs, err)
|
if c.TokenSource == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
var errs error
|
||||||
|
// Validate oidc.tokenSource mutual exclusivity with other fields of oidc
|
||||||
|
if c.ClientID != "" || c.ClientSecret != "" || c.Audience != "" ||
|
||||||
|
c.Scope != "" || c.TokenEndpointURL != "" || len(c.AdditionalEndpointParams) > 0 ||
|
||||||
|
c.TrustedCaFile != "" || c.InsecureSkipVerify || c.ProxyURL != "" {
|
||||||
|
errs = AppendError(errs, fmt.Errorf("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc"))
|
||||||
|
}
|
||||||
|
if c.TokenSource.Type == "exec" {
|
||||||
|
if !unsafeFeatures.IsEnabled(security.TokenSourceExec) {
|
||||||
|
errs = AppendError(errs, fmt.Errorf("unsafe feature %q is not enabled. "+
|
||||||
|
"To enable it, start frpc with '--allow-unsafe %s'", security.TokenSourceExec, security.TokenSourceExec))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := c.TokenSource.Validate(); err != nil {
|
||||||
|
errs = AppendError(errs, fmt.Errorf("invalid auth.oidc.tokenSource: %v", err))
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
if c.Transport.HeartbeatTimeout > 0 && c.Transport.HeartbeatInterval > 0 {
|
func validateTransportConfig(c *v1.ClientTransportConfig) (Warning, error) {
|
||||||
if c.Transport.HeartbeatTimeout < c.Transport.HeartbeatInterval {
|
var (
|
||||||
|
warnings Warning
|
||||||
|
errs error
|
||||||
|
)
|
||||||
|
|
||||||
|
if c.HeartbeatTimeout > 0 && c.HeartbeatInterval > 0 {
|
||||||
|
if c.HeartbeatTimeout < c.HeartbeatInterval {
|
||||||
errs = AppendError(errs, fmt.Errorf("invalid transport.heartbeatTimeout, heartbeat timeout should not less than heartbeat interval"))
|
errs = AppendError(errs, fmt.Errorf("invalid transport.heartbeatTimeout, heartbeat timeout should not less than heartbeat interval"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !lo.FromPtr(c.Transport.TLS.Enable) {
|
if !lo.FromPtr(c.TLS.Enable) {
|
||||||
checkTLSConfig := func(name string, value string) Warning {
|
checkTLSConfig := func(name string, value string) Warning {
|
||||||
if value != "" {
|
if value != "" {
|
||||||
return fmt.Errorf("%s is invalid when transport.tls.enable is false", name)
|
return fmt.Errorf("%s is invalid when transport.tls.enable is false", name)
|
||||||
@@ -94,16 +135,20 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.Unsa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
warnings = AppendError(warnings, checkTLSConfig("transport.tls.certFile", c.Transport.TLS.CertFile))
|
warnings = AppendError(warnings, checkTLSConfig("transport.tls.certFile", c.TLS.CertFile))
|
||||||
warnings = AppendError(warnings, checkTLSConfig("transport.tls.keyFile", c.Transport.TLS.KeyFile))
|
warnings = AppendError(warnings, checkTLSConfig("transport.tls.keyFile", c.TLS.KeyFile))
|
||||||
warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.Transport.TLS.TrustedCaFile))
|
warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.TLS.TrustedCaFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(SupportedTransportProtocols, c.Transport.Protocol) {
|
if !slices.Contains(SupportedTransportProtocols, c.Protocol) {
|
||||||
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
|
errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
|
||||||
}
|
}
|
||||||
|
return warnings, errs
|
||||||
|
}
|
||||||
|
|
||||||
for _, f := range c.IncludeConfigFiles {
|
func validateIncludeFiles(files []string) (Warning, error) {
|
||||||
|
var errs error
|
||||||
|
for _, f := range files {
|
||||||
absDir, err := filepath.Abs(filepath.Dir(f))
|
absDir, err := filepath.Abs(filepath.Dir(f))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = AppendError(errs, fmt.Errorf("include: parse directory of %s failed: %v", f, err))
|
errs = AppendError(errs, fmt.Errorf("include: parse directory of %s failed: %v", f, err))
|
||||||
@@ -113,14 +158,14 @@ func ValidateClientCommonConfig(c *v1.ClientCommonConfig, unsafeFeatures v1.Unsa
|
|||||||
errs = AppendError(errs, fmt.Errorf("include: directory of %s not exist", f))
|
errs = AppendError(errs, fmt.Errorf("include: directory of %s not exist", f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return warnings, errs
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateAllClientConfig(
|
func ValidateAllClientConfig(
|
||||||
c *v1.ClientCommonConfig,
|
c *v1.ClientCommonConfig,
|
||||||
proxyCfgs []v1.ProxyConfigurer,
|
proxyCfgs []v1.ProxyConfigurer,
|
||||||
visitorCfgs []v1.VisitorConfigurer,
|
visitorCfgs []v1.VisitorConfigurer,
|
||||||
unsafeFeatures v1.UnsafeFeatures,
|
unsafeFeatures *security.UnsafeFeatures,
|
||||||
) (Warning, error) {
|
) (Warning, error) {
|
||||||
var warnings Warning
|
var warnings Warning
|
||||||
if c != nil {
|
if c != nil {
|
||||||
|
|||||||
@@ -86,10 +86,6 @@ func (d *Dispatcher) Send(m Message) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Dispatcher) SendChannel() chan Message {
|
|
||||||
return d.sendCh
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Dispatcher) RegisterHandler(msg Message, handler func(Message)) {
|
func (d *Dispatcher) RegisterHandler(msg Message, handler func(Message)) {
|
||||||
d.msgHandlers[reflect.TypeOf(msg)] = handler
|
d.msgHandlers[reflect.TypeOf(msg)] = handler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package security
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenSourceExec = "TokenSourceExec"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ClientUnsafeFeatures = []string{
|
||||||
|
TokenSourceExec,
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerUnsafeFeatures = []string{
|
||||||
|
TokenSourceExec,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type UnsafeFeatures struct {
|
||||||
|
features map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnsafeFeatures(allowed []string) *UnsafeFeatures {
|
||||||
|
features := make(map[string]bool)
|
||||||
|
for _, f := range allowed {
|
||||||
|
features[f] = true
|
||||||
|
}
|
||||||
|
return &UnsafeFeatures{features: features}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UnsafeFeatures) IsEnabled(feature string) bool {
|
||||||
|
if u == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return u.features[feature]
|
||||||
|
}
|
||||||
@@ -35,15 +35,19 @@ type MessageTransporter interface {
|
|||||||
DispatchWithType(m msg.Message, msgType, laneKey string) bool
|
DispatchWithType(m msg.Message, msgType, laneKey string) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageTransporter(sendCh chan msg.Message) MessageTransporter {
|
type MessageSender interface {
|
||||||
|
Send(msg.Message) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMessageTransporter(sender MessageSender) MessageTransporter {
|
||||||
return &transporterImpl{
|
return &transporterImpl{
|
||||||
sendCh: sendCh,
|
sender: sender,
|
||||||
registry: make(map[string]map[string]chan msg.Message),
|
registry: make(map[string]map[string]chan msg.Message),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type transporterImpl struct {
|
type transporterImpl struct {
|
||||||
sendCh chan msg.Message
|
sender MessageSender
|
||||||
|
|
||||||
// First key is message type and second key is lane key.
|
// First key is message type and second key is lane key.
|
||||||
// Dispatch will dispatch message to related channel by its message type
|
// Dispatch will dispatch message to related channel by its message type
|
||||||
@@ -53,9 +57,7 @@ type transporterImpl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (impl *transporterImpl) Send(m msg.Message) error {
|
func (impl *transporterImpl) Send(m msg.Message) error {
|
||||||
return errors.PanicToError(func() {
|
return impl.sender.Send(m)
|
||||||
impl.sendCh <- m
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (impl *transporterImpl) Do(ctx context.Context, req msg.Message, laneKey, recvMsgType string) (msg.Message, error) {
|
func (impl *transporterImpl) Do(ctx context.Context, req msg.Message, laneKey, recvMsgType string) (msg.Message, error) {
|
||||||
|
|||||||
+1
-1
@@ -195,7 +195,7 @@ func NewControl(
|
|||||||
ctl.msgDispatcher = msg.NewDispatcher(ctl.conn)
|
ctl.msgDispatcher = msg.NewDispatcher(ctl.conn)
|
||||||
}
|
}
|
||||||
ctl.registerMsgHandlers()
|
ctl.registerMsgHandlers()
|
||||||
ctl.msgTransporter = transport.NewMessageTransporter(ctl.msgDispatcher.SendChannel())
|
ctl.msgTransporter = transport.NewMessageTransporter(ctl.msgDispatcher)
|
||||||
return ctl, nil
|
return ctl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user