proxy.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // Copyright 2023 The frp Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package validation
  15. import (
  16. "errors"
  17. "fmt"
  18. "slices"
  19. "strings"
  20. "k8s.io/apimachinery/pkg/util/validation"
  21. v1 "github.com/fatedier/frp/pkg/config/v1"
  22. )
  23. func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
  24. if c.Name == "" {
  25. return errors.New("name should not be empty")
  26. }
  27. if err := ValidateAnnotations(c.Annotations); err != nil {
  28. return err
  29. }
  30. if !slices.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) {
  31. return fmt.Errorf("not support proxy protocol version: %s", c.Transport.ProxyProtocolVersion)
  32. }
  33. if !slices.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) {
  34. return fmt.Errorf("bandwidth limit mode should be client or server")
  35. }
  36. if c.Plugin.Type == "" {
  37. if err := ValidatePort(c.LocalPort, "localPort"); err != nil {
  38. return fmt.Errorf("localPort: %v", err)
  39. }
  40. }
  41. if !slices.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) {
  42. return fmt.Errorf("not support health check type: %s", c.HealthCheck.Type)
  43. }
  44. if c.HealthCheck.Type != "" {
  45. if c.HealthCheck.Type == "http" &&
  46. c.HealthCheck.Path == "" {
  47. return fmt.Errorf("health check path should not be empty")
  48. }
  49. }
  50. if c.Plugin.Type != "" {
  51. if err := ValidateClientPluginOptions(c.Plugin.ClientPluginOptions); err != nil {
  52. return fmt.Errorf("plugin %s: %v", c.Plugin.Type, err)
  53. }
  54. }
  55. return nil
  56. }
  57. func validateProxyBaseConfigForServer(c *v1.ProxyBaseConfig) error {
  58. if err := ValidateAnnotations(c.Annotations); err != nil {
  59. return err
  60. }
  61. return nil
  62. }
  63. func validateDomainConfigForClient(c *v1.DomainConfig) error {
  64. if c.SubDomain == "" && len(c.CustomDomains) == 0 {
  65. return errors.New("subdomain and custom domains should not be both empty")
  66. }
  67. return nil
  68. }
  69. func validateDomainConfigForServer(c *v1.DomainConfig, s *v1.ServerConfig) error {
  70. for _, domain := range c.CustomDomains {
  71. if s.SubDomainHost != "" && len(strings.Split(s.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
  72. if strings.Contains(domain, s.SubDomainHost) {
  73. return fmt.Errorf("custom domain [%s] should not belong to subdomain host [%s]", domain, s.SubDomainHost)
  74. }
  75. }
  76. }
  77. if c.SubDomain != "" {
  78. if s.SubDomainHost == "" {
  79. return errors.New("subdomain is not supported because this feature is not enabled in server")
  80. }
  81. if strings.Contains(c.SubDomain, ".") || strings.Contains(c.SubDomain, "*") {
  82. return errors.New("'.' and '*' are not supported in subdomain")
  83. }
  84. }
  85. return nil
  86. }
  87. func ValidateProxyConfigurerForClient(c v1.ProxyConfigurer) error {
  88. base := c.GetBaseConfig()
  89. if err := validateProxyBaseConfigForClient(base); err != nil {
  90. return err
  91. }
  92. switch v := c.(type) {
  93. case *v1.TCPProxyConfig:
  94. return validateTCPProxyConfigForClient(v)
  95. case *v1.UDPProxyConfig:
  96. return validateUDPProxyConfigForClient(v)
  97. case *v1.TCPMuxProxyConfig:
  98. return validateTCPMuxProxyConfigForClient(v)
  99. case *v1.HTTPProxyConfig:
  100. return validateHTTPProxyConfigForClient(v)
  101. case *v1.HTTPSProxyConfig:
  102. return validateHTTPSProxyConfigForClient(v)
  103. case *v1.STCPProxyConfig:
  104. return validateSTCPProxyConfigForClient(v)
  105. case *v1.XTCPProxyConfig:
  106. return validateXTCPProxyConfigForClient(v)
  107. case *v1.SUDPProxyConfig:
  108. return validateSUDPProxyConfigForClient(v)
  109. }
  110. return errors.New("unknown proxy config type")
  111. }
  112. func validateTCPProxyConfigForClient(c *v1.TCPProxyConfig) error {
  113. return nil
  114. }
  115. func validateUDPProxyConfigForClient(c *v1.UDPProxyConfig) error {
  116. return nil
  117. }
  118. func validateTCPMuxProxyConfigForClient(c *v1.TCPMuxProxyConfig) error {
  119. if err := validateDomainConfigForClient(&c.DomainConfig); err != nil {
  120. return err
  121. }
  122. if !slices.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) {
  123. return fmt.Errorf("not support multiplexer: %s", c.Multiplexer)
  124. }
  125. return nil
  126. }
  127. func validateHTTPProxyConfigForClient(c *v1.HTTPProxyConfig) error {
  128. return validateDomainConfigForClient(&c.DomainConfig)
  129. }
  130. func validateHTTPSProxyConfigForClient(c *v1.HTTPSProxyConfig) error {
  131. return validateDomainConfigForClient(&c.DomainConfig)
  132. }
  133. func validateSTCPProxyConfigForClient(c *v1.STCPProxyConfig) error {
  134. return nil
  135. }
  136. func validateXTCPProxyConfigForClient(c *v1.XTCPProxyConfig) error {
  137. return nil
  138. }
  139. func validateSUDPProxyConfigForClient(c *v1.SUDPProxyConfig) error {
  140. return nil
  141. }
  142. func ValidateProxyConfigurerForServer(c v1.ProxyConfigurer, s *v1.ServerConfig) error {
  143. base := c.GetBaseConfig()
  144. if err := validateProxyBaseConfigForServer(base); err != nil {
  145. return err
  146. }
  147. switch v := c.(type) {
  148. case *v1.TCPProxyConfig:
  149. return validateTCPProxyConfigForServer(v, s)
  150. case *v1.UDPProxyConfig:
  151. return validateUDPProxyConfigForServer(v, s)
  152. case *v1.TCPMuxProxyConfig:
  153. return validateTCPMuxProxyConfigForServer(v, s)
  154. case *v1.HTTPProxyConfig:
  155. return validateHTTPProxyConfigForServer(v, s)
  156. case *v1.HTTPSProxyConfig:
  157. return validateHTTPSProxyConfigForServer(v, s)
  158. case *v1.STCPProxyConfig:
  159. return validateSTCPProxyConfigForServer(v, s)
  160. case *v1.XTCPProxyConfig:
  161. return validateXTCPProxyConfigForServer(v, s)
  162. case *v1.SUDPProxyConfig:
  163. return validateSUDPProxyConfigForServer(v, s)
  164. default:
  165. return errors.New("unknown proxy config type")
  166. }
  167. }
  168. func validateTCPProxyConfigForServer(c *v1.TCPProxyConfig, s *v1.ServerConfig) error {
  169. return nil
  170. }
  171. func validateUDPProxyConfigForServer(c *v1.UDPProxyConfig, s *v1.ServerConfig) error {
  172. return nil
  173. }
  174. func validateTCPMuxProxyConfigForServer(c *v1.TCPMuxProxyConfig, s *v1.ServerConfig) error {
  175. if c.Multiplexer == string(v1.TCPMultiplexerHTTPConnect) &&
  176. s.TCPMuxHTTPConnectPort == 0 {
  177. return fmt.Errorf("tcpmux with multiplexer httpconnect not supported because this feature is not enabled in server")
  178. }
  179. return validateDomainConfigForServer(&c.DomainConfig, s)
  180. }
  181. func validateHTTPProxyConfigForServer(c *v1.HTTPProxyConfig, s *v1.ServerConfig) error {
  182. if s.VhostHTTPPort == 0 {
  183. return fmt.Errorf("type [http] not supported when vhost http port is not set")
  184. }
  185. return validateDomainConfigForServer(&c.DomainConfig, s)
  186. }
  187. func validateHTTPSProxyConfigForServer(c *v1.HTTPSProxyConfig, s *v1.ServerConfig) error {
  188. if s.VhostHTTPSPort == 0 {
  189. return fmt.Errorf("type [https] not supported when vhost https port is not set")
  190. }
  191. return validateDomainConfigForServer(&c.DomainConfig, s)
  192. }
  193. func validateSTCPProxyConfigForServer(c *v1.STCPProxyConfig, s *v1.ServerConfig) error {
  194. return nil
  195. }
  196. func validateXTCPProxyConfigForServer(c *v1.XTCPProxyConfig, s *v1.ServerConfig) error {
  197. return nil
  198. }
  199. func validateSUDPProxyConfigForServer(c *v1.SUDPProxyConfig, s *v1.ServerConfig) error {
  200. return nil
  201. }
  202. // ValidateAnnotations validates that a set of annotations are correctly defined.
  203. func ValidateAnnotations(annotations map[string]string) error {
  204. if len(annotations) == 0 {
  205. return nil
  206. }
  207. var errs error
  208. for k := range annotations {
  209. for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
  210. errs = AppendError(errs, fmt.Errorf("annotation key %s is invalid: %s", k, msg))
  211. }
  212. }
  213. if err := ValidateAnnotationsSize(annotations); err != nil {
  214. errs = AppendError(errs, err)
  215. }
  216. return errs
  217. }
  218. const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
  219. func ValidateAnnotationsSize(annotations map[string]string) error {
  220. var totalSize int64
  221. for k, v := range annotations {
  222. totalSize += (int64)(len(k)) + (int64)(len(v))
  223. }
  224. if totalSize > (int64)(TotalAnnotationSizeLimitB) {
  225. return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
  226. }
  227. return nil
  228. }