@@ -23,87 +23,132 @@ import (
2323 "github.com/samber/lo"
2424
2525 v1 "github.com/fatedier/frp/pkg/config/v1"
26- "github.com/fatedier/frp/pkg/featuregate"
26+ "github.com/fatedier/frp/pkg/policy/featuregate"
27+ "github.com/fatedier/frp/pkg/policy/security"
2728)
2829
29- func ValidateClientCommonConfig (c * v1.ClientCommonConfig , unsafeFeatures v1 .UnsafeFeatures ) (Warning , error ) {
30+ func ValidateClientCommonConfig (c * v1.ClientCommonConfig , unsafeFeatures * security .UnsafeFeatures ) (Warning , error ) {
3031 var (
3132 warnings Warning
3233 errs error
3334 )
34- // validate feature gates
35+
36+ validators := []func () (Warning , error ){
37+ func () (Warning , error ) { return validateFeatureGates (c ) },
38+ func () (Warning , error ) { return validateAuthConfig (& c .Auth , unsafeFeatures ) },
39+ func () (Warning , error ) { return nil , validateLogConfig (& c .Log ) },
40+ func () (Warning , error ) { return nil , validateWebServerConfig (& c .WebServer ) },
41+ func () (Warning , error ) { return validateTransportConfig (& c .Transport ) },
42+ func () (Warning , error ) { return validateIncludeFiles (c .IncludeConfigFiles ) },
43+ }
44+
45+ for _ , v := range validators {
46+ w , err := v ()
47+ warnings = AppendError (warnings , w )
48+ errs = AppendError (errs , err )
49+ }
50+ return warnings , errs
51+ }
52+
53+ func validateFeatureGates (c * v1.ClientCommonConfig ) (Warning , error ) {
3554 if c .VirtualNet .Address != "" {
3655 if ! featuregate .Enabled (featuregate .VirtualNet ) {
37- return warnings , fmt .Errorf ("VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag" )
56+ return nil , fmt .Errorf ("VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag" )
3857 }
3958 }
59+ return nil , nil
60+ }
4061
41- if ! slices .Contains (SupportedAuthMethods , c .Auth .Method ) {
62+ func validateAuthConfig (c * v1.AuthClientConfig , unsafeFeatures * security.UnsafeFeatures ) (Warning , error ) {
63+ var errs error
64+ if ! slices .Contains (SupportedAuthMethods , c .Method ) {
4265 errs = AppendError (errs , fmt .Errorf ("invalid auth method, optional values are %v" , SupportedAuthMethods ))
4366 }
44- if ! lo .Every (SupportedAuthAdditionalScopes , c .Auth . AdditionalScopes ) {
67+ if ! lo .Every (SupportedAuthAdditionalScopes , c .AdditionalScopes ) {
4568 errs = AppendError (errs , fmt .Errorf ("invalid auth additional scopes, optional values are %v" , SupportedAuthAdditionalScopes ))
4669 }
4770
4871 // Validate token/tokenSource mutual exclusivity
49- if c .Auth . Token != "" && c . Auth .TokenSource != nil {
72+ if c .Token != "" && c .TokenSource != nil {
5073 errs = AppendError (errs , fmt .Errorf ("cannot specify both auth.token and auth.tokenSource" ))
5174 }
5275
5376 // Validate tokenSource if specified
54- if c .Auth .TokenSource != nil {
55- if c .Auth .TokenSource .Type == "exec" && ! unsafeFeatures .IsEnabled (v1 .UnsafeFeatureTokenSourceExec ) {
56- errs = AppendError (errs , fmt .Errorf ("unsafe 'exec' not allowed for auth.tokenSource.type" ))
77+ if c .TokenSource != nil {
78+ if c .TokenSource .Type == "exec" {
79+ if ! unsafeFeatures .IsEnabled (security .TokenSourceExec ) {
80+ errs = AppendError (errs , fmt .Errorf ("unsafe feature %q is not enabled. " +
81+ "To enable it, start frpc with '--allow-unsafe %s'" , security .TokenSourceExec , security .TokenSourceExec ))
82+ }
5783 }
58- if err := c .Auth . TokenSource .Validate (); err != nil {
84+ if err := c .TokenSource .Validate (); err != nil {
5985 errs = AppendError (errs , fmt .Errorf ("invalid auth.tokenSource: %v" , err ))
6086 }
6187 }
6288
63- if c .Auth .OIDC .TokenSource != nil {
64- // Validate oidc.tokenSource mutual exclusivity with other fields of oidc
65- if c .Auth .OIDC .ClientID != "" || c .Auth .OIDC .ClientSecret != "" || c .Auth .OIDC .Audience != "" ||
66- c .Auth .OIDC .Scope != "" || c .Auth .OIDC .TokenEndpointURL != "" || len (c .Auth .OIDC .AdditionalEndpointParams ) > 0 ||
67- c .Auth .OIDC .TrustedCaFile != "" || c .Auth .OIDC .InsecureSkipVerify || c .Auth .OIDC .ProxyURL != "" {
68- errs = AppendError (errs , fmt .Errorf ("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc" ))
69- }
70- if c .Auth .OIDC .TokenSource .Type == "exec" && ! unsafeFeatures .IsEnabled (v1 .UnsafeFeatureTokenSourceExec ) {
71- errs = AppendError (errs , fmt .Errorf ("unsafe 'exec' not allowed for auth.oidc.tokenSource.type" ))
72- }
73- }
74-
75- if err := validateLogConfig (& c .Log ); err != nil {
89+ if err := validateOIDCConfig (& c .OIDC , unsafeFeatures ); err != nil {
7690 errs = AppendError (errs , err )
7791 }
92+ return nil , errs
93+ }
7894
79- if err := validateWebServerConfig (& c .WebServer ); err != nil {
80- errs = AppendError (errs , err )
95+ func validateOIDCConfig (c * v1.AuthOIDCClientConfig , unsafeFeatures * security.UnsafeFeatures ) error {
96+ if c .TokenSource == nil {
97+ return nil
98+ }
99+ var errs error
100+ // Validate oidc.tokenSource mutual exclusivity with other fields of oidc
101+ if c .ClientID != "" || c .ClientSecret != "" || c .Audience != "" ||
102+ c .Scope != "" || c .TokenEndpointURL != "" || len (c .AdditionalEndpointParams ) > 0 ||
103+ c .TrustedCaFile != "" || c .InsecureSkipVerify || c .ProxyURL != "" {
104+ errs = AppendError (errs , fmt .Errorf ("cannot specify both auth.oidc.tokenSource and any other field of auth.oidc" ))
105+ }
106+ if c .TokenSource .Type == "exec" {
107+ if ! unsafeFeatures .IsEnabled (security .TokenSourceExec ) {
108+ errs = AppendError (errs , fmt .Errorf ("unsafe feature %q is not enabled. " +
109+ "To enable it, start frpc with '--allow-unsafe %s'" , security .TokenSourceExec , security .TokenSourceExec ))
110+ }
81111 }
112+ if err := c .TokenSource .Validate (); err != nil {
113+ errs = AppendError (errs , fmt .Errorf ("invalid auth.oidc.tokenSource: %v" , err ))
114+ }
115+ return errs
116+ }
117+
118+ func validateTransportConfig (c * v1.ClientTransportConfig ) (Warning , error ) {
119+ var (
120+ warnings Warning
121+ errs error
122+ )
82123
83- if c .Transport . HeartbeatTimeout > 0 && c . Transport .HeartbeatInterval > 0 {
84- if c .Transport . HeartbeatTimeout < c . Transport .HeartbeatInterval {
124+ if c .HeartbeatTimeout > 0 && c .HeartbeatInterval > 0 {
125+ if c .HeartbeatTimeout < c .HeartbeatInterval {
85126 errs = AppendError (errs , fmt .Errorf ("invalid transport.heartbeatTimeout, heartbeat timeout should not less than heartbeat interval" ))
86127 }
87128 }
88129
89- if ! lo .FromPtr (c .Transport . TLS .Enable ) {
130+ if ! lo .FromPtr (c .TLS .Enable ) {
90131 checkTLSConfig := func (name string , value string ) Warning {
91132 if value != "" {
92133 return fmt .Errorf ("%s is invalid when transport.tls.enable is false" , name )
93134 }
94135 return nil
95136 }
96137
97- warnings = AppendError (warnings , checkTLSConfig ("transport.tls.certFile" , c .Transport . TLS .CertFile ))
98- warnings = AppendError (warnings , checkTLSConfig ("transport.tls.keyFile" , c .Transport . TLS .KeyFile ))
99- warnings = AppendError (warnings , checkTLSConfig ("transport.tls.trustedCaFile" , c .Transport . TLS .TrustedCaFile ))
138+ warnings = AppendError (warnings , checkTLSConfig ("transport.tls.certFile" , c .TLS .CertFile ))
139+ warnings = AppendError (warnings , checkTLSConfig ("transport.tls.keyFile" , c .TLS .KeyFile ))
140+ warnings = AppendError (warnings , checkTLSConfig ("transport.tls.trustedCaFile" , c .TLS .TrustedCaFile ))
100141 }
101142
102- if ! slices .Contains (SupportedTransportProtocols , c .Transport . Protocol ) {
143+ if ! slices .Contains (SupportedTransportProtocols , c .Protocol ) {
103144 errs = AppendError (errs , fmt .Errorf ("invalid transport.protocol, optional values are %v" , SupportedTransportProtocols ))
104145 }
146+ return warnings , errs
147+ }
105148
106- for _ , f := range c .IncludeConfigFiles {
149+ func validateIncludeFiles (files []string ) (Warning , error ) {
150+ var errs error
151+ for _ , f := range files {
107152 absDir , err := filepath .Abs (filepath .Dir (f ))
108153 if err != nil {
109154 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
113158 errs = AppendError (errs , fmt .Errorf ("include: directory of %s not exist" , f ))
114159 }
115160 }
116- return warnings , errs
161+ return nil , errs
117162}
118163
119164func ValidateAllClientConfig (
120165 c * v1.ClientCommonConfig ,
121166 proxyCfgs []v1.ProxyConfigurer ,
122167 visitorCfgs []v1.VisitorConfigurer ,
123- unsafeFeatures v1 .UnsafeFeatures ,
168+ unsafeFeatures * security .UnsafeFeatures ,
124169) (Warning , error ) {
125170 var warnings Warning
126171 if c != nil {
0 commit comments