123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- // Copyright 2023 The frp Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package validation
- import (
- "errors"
- "fmt"
- "slices"
- "strings"
- "k8s.io/apimachinery/pkg/util/validation"
- v1 "github.com/fatedier/frp/pkg/config/v1"
- )
- func validateProxyBaseConfigForClient(c *v1.ProxyBaseConfig) error {
- if c.Name == "" {
- return errors.New("name should not be empty")
- }
- if err := ValidateAnnotations(c.Annotations); err != nil {
- return err
- }
- if !slices.Contains([]string{"", "v1", "v2"}, c.Transport.ProxyProtocolVersion) {
- return fmt.Errorf("not support proxy protocol version: %s", c.Transport.ProxyProtocolVersion)
- }
- if !slices.Contains([]string{"client", "server"}, c.Transport.BandwidthLimitMode) {
- return fmt.Errorf("bandwidth limit mode should be client or server")
- }
- if c.Plugin.Type == "" {
- if err := ValidatePort(c.LocalPort, "localPort"); err != nil {
- return fmt.Errorf("localPort: %v", err)
- }
- }
- if !slices.Contains([]string{"", "tcp", "http"}, c.HealthCheck.Type) {
- return fmt.Errorf("not support health check type: %s", c.HealthCheck.Type)
- }
- if c.HealthCheck.Type != "" {
- if c.HealthCheck.Type == "http" &&
- c.HealthCheck.Path == "" {
- return fmt.Errorf("health check path should not be empty")
- }
- }
- if c.Plugin.Type != "" {
- if err := ValidateClientPluginOptions(c.Plugin.ClientPluginOptions); err != nil {
- return fmt.Errorf("plugin %s: %v", c.Plugin.Type, err)
- }
- }
- return nil
- }
- func validateProxyBaseConfigForServer(c *v1.ProxyBaseConfig) error {
- if err := ValidateAnnotations(c.Annotations); err != nil {
- return err
- }
- return nil
- }
- func validateDomainConfigForClient(c *v1.DomainConfig) error {
- if c.SubDomain == "" && len(c.CustomDomains) == 0 {
- return errors.New("subdomain and custom domains should not be both empty")
- }
- return nil
- }
- func validateDomainConfigForServer(c *v1.DomainConfig, s *v1.ServerConfig) error {
- for _, domain := range c.CustomDomains {
- if s.SubDomainHost != "" && len(strings.Split(s.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
- if strings.Contains(domain, s.SubDomainHost) {
- return fmt.Errorf("custom domain [%s] should not belong to subdomain host [%s]", domain, s.SubDomainHost)
- }
- }
- }
- if c.SubDomain != "" {
- if s.SubDomainHost == "" {
- return errors.New("subdomain is not supported because this feature is not enabled in server")
- }
- if strings.Contains(c.SubDomain, ".") || strings.Contains(c.SubDomain, "*") {
- return errors.New("'.' and '*' are not supported in subdomain")
- }
- }
- return nil
- }
- func ValidateProxyConfigurerForClient(c v1.ProxyConfigurer) error {
- base := c.GetBaseConfig()
- if err := validateProxyBaseConfigForClient(base); err != nil {
- return err
- }
- switch v := c.(type) {
- case *v1.TCPProxyConfig:
- return validateTCPProxyConfigForClient(v)
- case *v1.UDPProxyConfig:
- return validateUDPProxyConfigForClient(v)
- case *v1.TCPMuxProxyConfig:
- return validateTCPMuxProxyConfigForClient(v)
- case *v1.HTTPProxyConfig:
- return validateHTTPProxyConfigForClient(v)
- case *v1.HTTPSProxyConfig:
- return validateHTTPSProxyConfigForClient(v)
- case *v1.STCPProxyConfig:
- return validateSTCPProxyConfigForClient(v)
- case *v1.XTCPProxyConfig:
- return validateXTCPProxyConfigForClient(v)
- case *v1.SUDPProxyConfig:
- return validateSUDPProxyConfigForClient(v)
- }
- return errors.New("unknown proxy config type")
- }
- func validateTCPProxyConfigForClient(c *v1.TCPProxyConfig) error {
- return nil
- }
- func validateUDPProxyConfigForClient(c *v1.UDPProxyConfig) error {
- return nil
- }
- func validateTCPMuxProxyConfigForClient(c *v1.TCPMuxProxyConfig) error {
- if err := validateDomainConfigForClient(&c.DomainConfig); err != nil {
- return err
- }
- if !slices.Contains([]string{string(v1.TCPMultiplexerHTTPConnect)}, c.Multiplexer) {
- return fmt.Errorf("not support multiplexer: %s", c.Multiplexer)
- }
- return nil
- }
- func validateHTTPProxyConfigForClient(c *v1.HTTPProxyConfig) error {
- return validateDomainConfigForClient(&c.DomainConfig)
- }
- func validateHTTPSProxyConfigForClient(c *v1.HTTPSProxyConfig) error {
- return validateDomainConfigForClient(&c.DomainConfig)
- }
- func validateSTCPProxyConfigForClient(c *v1.STCPProxyConfig) error {
- return nil
- }
- func validateXTCPProxyConfigForClient(c *v1.XTCPProxyConfig) error {
- return nil
- }
- func validateSUDPProxyConfigForClient(c *v1.SUDPProxyConfig) error {
- return nil
- }
- func ValidateProxyConfigurerForServer(c v1.ProxyConfigurer, s *v1.ServerConfig) error {
- base := c.GetBaseConfig()
- if err := validateProxyBaseConfigForServer(base); err != nil {
- return err
- }
- switch v := c.(type) {
- case *v1.TCPProxyConfig:
- return validateTCPProxyConfigForServer(v, s)
- case *v1.UDPProxyConfig:
- return validateUDPProxyConfigForServer(v, s)
- case *v1.TCPMuxProxyConfig:
- return validateTCPMuxProxyConfigForServer(v, s)
- case *v1.HTTPProxyConfig:
- return validateHTTPProxyConfigForServer(v, s)
- case *v1.HTTPSProxyConfig:
- return validateHTTPSProxyConfigForServer(v, s)
- case *v1.STCPProxyConfig:
- return validateSTCPProxyConfigForServer(v, s)
- case *v1.XTCPProxyConfig:
- return validateXTCPProxyConfigForServer(v, s)
- case *v1.SUDPProxyConfig:
- return validateSUDPProxyConfigForServer(v, s)
- default:
- return errors.New("unknown proxy config type")
- }
- }
- func validateTCPProxyConfigForServer(c *v1.TCPProxyConfig, s *v1.ServerConfig) error {
- return nil
- }
- func validateUDPProxyConfigForServer(c *v1.UDPProxyConfig, s *v1.ServerConfig) error {
- return nil
- }
- func validateTCPMuxProxyConfigForServer(c *v1.TCPMuxProxyConfig, s *v1.ServerConfig) error {
- if c.Multiplexer == string(v1.TCPMultiplexerHTTPConnect) &&
- s.TCPMuxHTTPConnectPort == 0 {
- return fmt.Errorf("tcpmux with multiplexer httpconnect not supported because this feature is not enabled in server")
- }
- return validateDomainConfigForServer(&c.DomainConfig, s)
- }
- func validateHTTPProxyConfigForServer(c *v1.HTTPProxyConfig, s *v1.ServerConfig) error {
- if s.VhostHTTPPort == 0 {
- return fmt.Errorf("type [http] not supported when vhost http port is not set")
- }
- return validateDomainConfigForServer(&c.DomainConfig, s)
- }
- func validateHTTPSProxyConfigForServer(c *v1.HTTPSProxyConfig, s *v1.ServerConfig) error {
- if s.VhostHTTPSPort == 0 {
- return fmt.Errorf("type [https] not supported when vhost https port is not set")
- }
- return validateDomainConfigForServer(&c.DomainConfig, s)
- }
- func validateSTCPProxyConfigForServer(c *v1.STCPProxyConfig, s *v1.ServerConfig) error {
- return nil
- }
- func validateXTCPProxyConfigForServer(c *v1.XTCPProxyConfig, s *v1.ServerConfig) error {
- return nil
- }
- func validateSUDPProxyConfigForServer(c *v1.SUDPProxyConfig, s *v1.ServerConfig) error {
- return nil
- }
- // ValidateAnnotations validates that a set of annotations are correctly defined.
- func ValidateAnnotations(annotations map[string]string) error {
- if len(annotations) == 0 {
- return nil
- }
- var errs error
- for k := range annotations {
- for _, msg := range validation.IsQualifiedName(strings.ToLower(k)) {
- errs = AppendError(errs, fmt.Errorf("annotation key %s is invalid: %s", k, msg))
- }
- }
- if err := ValidateAnnotationsSize(annotations); err != nil {
- errs = AppendError(errs, err)
- }
- return errs
- }
- const TotalAnnotationSizeLimitB int = 256 * (1 << 10) // 256 kB
- func ValidateAnnotationsSize(annotations map[string]string) error {
- var totalSize int64
- for k, v := range annotations {
- totalSize += (int64)(len(k)) + (int64)(len(v))
- }
- if totalSize > (int64)(TotalAnnotationSizeLimitB) {
- return fmt.Errorf("annotations size %d is larger than limit %d", totalSize, TotalAnnotationSizeLimitB)
- }
- return nil
- }
|