123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- // 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 v1
- import (
- "bytes"
- "encoding/json"
- "errors"
- "fmt"
- "reflect"
- "github.com/samber/lo"
- "github.com/fatedier/frp/pkg/config/types"
- "github.com/fatedier/frp/pkg/msg"
- "github.com/fatedier/frp/pkg/util/util"
- )
- type ProxyTransport struct {
- // UseEncryption controls whether or not communication with the server will
- // be encrypted. Encryption is done using the tokens supplied in the server
- // and client configuration.
- UseEncryption bool `json:"useEncryption,omitempty"`
- // UseCompression controls whether or not communication with the server
- // will be compressed.
- UseCompression bool `json:"useCompression,omitempty"`
- // BandwidthLimit limit the bandwidth
- // 0 means no limit
- BandwidthLimit types.BandwidthQuantity `json:"bandwidthLimit,omitempty"`
- // BandwidthLimitMode specifies whether to limit the bandwidth on the
- // client or server side. Valid values include "client" and "server".
- // By default, this value is "client".
- BandwidthLimitMode string `json:"bandwidthLimitMode,omitempty"`
- // ProxyProtocolVersion specifies which protocol version to use. Valid
- // values include "v1", "v2", and "". If the value is "", a protocol
- // version will be automatically selected. By default, this value is "".
- ProxyProtocolVersion string `json:"proxyProtocolVersion,omitempty"`
- }
- type LoadBalancerConfig struct {
- // Group specifies which group the is a part of. The server will use
- // this information to load balance proxies in the same group. If the value
- // is "", this will not be in a group.
- Group string `json:"group"`
- // GroupKey specifies a group key, which should be the same among proxies
- // of the same group.
- GroupKey string `json:"groupKey,omitempty"`
- }
- type ProxyBackend struct {
- // LocalIP specifies the IP address or host name of the backend.
- LocalIP string `json:"localIP,omitempty"`
- // LocalPort specifies the port of the backend.
- LocalPort int `json:"localPort,omitempty"`
- // Plugin specifies what plugin should be used for handling connections. If this value
- // is set, the LocalIP and LocalPort values will be ignored.
- Plugin TypedClientPluginOptions `json:"plugin,omitempty"`
- }
- // HealthCheckConfig configures health checking. This can be useful for load
- // balancing purposes to detect and remove proxies to failing services.
- type HealthCheckConfig struct {
- // Type specifies what protocol to use for health checking.
- // Valid values include "tcp", "http", and "". If this value is "", health
- // checking will not be performed.
- //
- // If the type is "tcp", a connection will be attempted to the target
- // server. If a connection cannot be established, the health check fails.
- //
- // If the type is "http", a GET request will be made to the endpoint
- // specified by HealthCheckURL. If the response is not a 200, the health
- // check fails.
- Type string `json:"type"` // tcp | http
- // TimeoutSeconds specifies the number of seconds to wait for a health
- // check attempt to connect. If the timeout is reached, this counts as a
- // health check failure. By default, this value is 3.
- TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
- // MaxFailed specifies the number of allowed failures before the
- // is stopped. By default, this value is 1.
- MaxFailed int `json:"maxFailed,omitempty"`
- // IntervalSeconds specifies the time in seconds between health
- // checks. By default, this value is 10.
- IntervalSeconds int `json:"intervalSeconds"`
- // Path specifies the path to send health checks to if the
- // health check type is "http".
- Path string `json:"path,omitempty"`
- // HTTPHeaders specifies the headers to send with the health request, if
- // the health check type is "http".
- HTTPHeaders []HTTPHeader `json:"httpHeaders,omitempty"`
- }
- type DomainConfig struct {
- CustomDomains []string `json:"customDomains,omitempty"`
- SubDomain string `json:"subdomain,omitempty"`
- }
- type ProxyBaseConfig struct {
- Name string `json:"name"`
- Type string `json:"type"`
- Annotations map[string]string `json:"annotations,omitempty"`
- Transport ProxyTransport `json:"transport,omitempty"`
- // metadata info for each proxy
- Metadatas map[string]string `json:"metadatas,omitempty"`
- LoadBalancer LoadBalancerConfig `json:"loadBalancer,omitempty"`
- HealthCheck HealthCheckConfig `json:"healthCheck,omitempty"`
- ProxyBackend
- }
- func (c *ProxyBaseConfig) GetBaseConfig() *ProxyBaseConfig {
- return c
- }
- func (c *ProxyBaseConfig) Complete(namePrefix string) {
- c.Name = lo.Ternary(namePrefix == "", "", namePrefix+".") + c.Name
- c.LocalIP = util.EmptyOr(c.LocalIP, "127.0.0.1")
- c.Transport.BandwidthLimitMode = util.EmptyOr(c.Transport.BandwidthLimitMode, types.BandwidthLimitModeClient)
- if c.Plugin.ClientPluginOptions != nil {
- c.Plugin.ClientPluginOptions.Complete()
- }
- }
- func (c *ProxyBaseConfig) MarshalToMsg(m *msg.NewProxy) {
- m.ProxyName = c.Name
- m.ProxyType = c.Type
- m.UseEncryption = c.Transport.UseEncryption
- m.UseCompression = c.Transport.UseCompression
- m.BandwidthLimit = c.Transport.BandwidthLimit.String()
- // leave it empty for default value to reduce traffic
- if c.Transport.BandwidthLimitMode != "client" {
- m.BandwidthLimitMode = c.Transport.BandwidthLimitMode
- }
- m.Group = c.LoadBalancer.Group
- m.GroupKey = c.LoadBalancer.GroupKey
- m.Metas = c.Metadatas
- m.Annotations = c.Annotations
- }
- func (c *ProxyBaseConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.Name = m.ProxyName
- c.Type = m.ProxyType
- c.Transport.UseEncryption = m.UseEncryption
- c.Transport.UseCompression = m.UseCompression
- if m.BandwidthLimit != "" {
- c.Transport.BandwidthLimit, _ = types.NewBandwidthQuantity(m.BandwidthLimit)
- }
- if m.BandwidthLimitMode != "" {
- c.Transport.BandwidthLimitMode = m.BandwidthLimitMode
- }
- c.LoadBalancer.Group = m.Group
- c.LoadBalancer.GroupKey = m.GroupKey
- c.Metadatas = m.Metas
- c.Annotations = m.Annotations
- }
- type TypedProxyConfig struct {
- Type string `json:"type"`
- ProxyConfigurer
- }
- func (c *TypedProxyConfig) UnmarshalJSON(b []byte) error {
- if len(b) == 4 && string(b) == "null" {
- return errors.New("type is required")
- }
- typeStruct := struct {
- Type string `json:"type"`
- }{}
- if err := json.Unmarshal(b, &typeStruct); err != nil {
- return err
- }
- c.Type = typeStruct.Type
- configurer := NewProxyConfigurerByType(ProxyType(typeStruct.Type))
- if configurer == nil {
- return fmt.Errorf("unknown proxy type: %s", typeStruct.Type)
- }
- decoder := json.NewDecoder(bytes.NewBuffer(b))
- if DisallowUnknownFields {
- decoder.DisallowUnknownFields()
- }
- if err := decoder.Decode(configurer); err != nil {
- return fmt.Errorf("unmarshal ProxyConfig error: %v", err)
- }
- c.ProxyConfigurer = configurer
- return nil
- }
- func (c *TypedProxyConfig) MarshalJSON() ([]byte, error) {
- return json.Marshal(c.ProxyConfigurer)
- }
- type ProxyConfigurer interface {
- Complete(namePrefix string)
- GetBaseConfig() *ProxyBaseConfig
- // MarshalToMsg marshals this config into a msg.NewProxy message. This
- // function will be called on the frpc side.
- MarshalToMsg(*msg.NewProxy)
- // UnmarshalFromMsg unmarshal a msg.NewProxy message into this config.
- // This function will be called on the frps side.
- UnmarshalFromMsg(*msg.NewProxy)
- }
- type ProxyType string
- const (
- ProxyTypeTCP ProxyType = "tcp"
- ProxyTypeUDP ProxyType = "udp"
- ProxyTypeTCPMUX ProxyType = "tcpmux"
- ProxyTypeHTTP ProxyType = "http"
- ProxyTypeHTTPS ProxyType = "https"
- ProxyTypeSTCP ProxyType = "stcp"
- ProxyTypeXTCP ProxyType = "xtcp"
- ProxyTypeSUDP ProxyType = "sudp"
- )
- var proxyConfigTypeMap = map[ProxyType]reflect.Type{
- ProxyTypeTCP: reflect.TypeOf(TCPProxyConfig{}),
- ProxyTypeUDP: reflect.TypeOf(UDPProxyConfig{}),
- ProxyTypeHTTP: reflect.TypeOf(HTTPProxyConfig{}),
- ProxyTypeHTTPS: reflect.TypeOf(HTTPSProxyConfig{}),
- ProxyTypeTCPMUX: reflect.TypeOf(TCPMuxProxyConfig{}),
- ProxyTypeSTCP: reflect.TypeOf(STCPProxyConfig{}),
- ProxyTypeXTCP: reflect.TypeOf(XTCPProxyConfig{}),
- ProxyTypeSUDP: reflect.TypeOf(SUDPProxyConfig{}),
- }
- func NewProxyConfigurerByType(proxyType ProxyType) ProxyConfigurer {
- v, ok := proxyConfigTypeMap[proxyType]
- if !ok {
- return nil
- }
- pc := reflect.New(v).Interface().(ProxyConfigurer)
- pc.GetBaseConfig().Type = string(proxyType)
- return pc
- }
- var _ ProxyConfigurer = &TCPProxyConfig{}
- type TCPProxyConfig struct {
- ProxyBaseConfig
- RemotePort int `json:"remotePort,omitempty"`
- }
- func (c *TCPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.RemotePort = c.RemotePort
- }
- func (c *TCPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.RemotePort = m.RemotePort
- }
- var _ ProxyConfigurer = &UDPProxyConfig{}
- type UDPProxyConfig struct {
- ProxyBaseConfig
- RemotePort int `json:"remotePort,omitempty"`
- }
- func (c *UDPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.RemotePort = c.RemotePort
- }
- func (c *UDPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.RemotePort = m.RemotePort
- }
- var _ ProxyConfigurer = &HTTPProxyConfig{}
- type HTTPProxyConfig struct {
- ProxyBaseConfig
- DomainConfig
- Locations []string `json:"locations,omitempty"`
- HTTPUser string `json:"httpUser,omitempty"`
- HTTPPassword string `json:"httpPassword,omitempty"`
- HostHeaderRewrite string `json:"hostHeaderRewrite,omitempty"`
- RequestHeaders HeaderOperations `json:"requestHeaders,omitempty"`
- ResponseHeaders HeaderOperations `json:"responseHeaders,omitempty"`
- RouteByHTTPUser string `json:"routeByHTTPUser,omitempty"`
- }
- func (c *HTTPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.CustomDomains = c.CustomDomains
- m.SubDomain = c.SubDomain
- m.Locations = c.Locations
- m.HostHeaderRewrite = c.HostHeaderRewrite
- m.HTTPUser = c.HTTPUser
- m.HTTPPwd = c.HTTPPassword
- m.Headers = c.RequestHeaders.Set
- m.ResponseHeaders = c.ResponseHeaders.Set
- m.RouteByHTTPUser = c.RouteByHTTPUser
- }
- func (c *HTTPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.CustomDomains = m.CustomDomains
- c.SubDomain = m.SubDomain
- c.Locations = m.Locations
- c.HostHeaderRewrite = m.HostHeaderRewrite
- c.HTTPUser = m.HTTPUser
- c.HTTPPassword = m.HTTPPwd
- c.RequestHeaders.Set = m.Headers
- c.ResponseHeaders.Set = m.ResponseHeaders
- c.RouteByHTTPUser = m.RouteByHTTPUser
- }
- var _ ProxyConfigurer = &HTTPSProxyConfig{}
- type HTTPSProxyConfig struct {
- ProxyBaseConfig
- DomainConfig
- }
- func (c *HTTPSProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.CustomDomains = c.CustomDomains
- m.SubDomain = c.SubDomain
- }
- func (c *HTTPSProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.CustomDomains = m.CustomDomains
- c.SubDomain = m.SubDomain
- }
- type TCPMultiplexerType string
- const (
- TCPMultiplexerHTTPConnect TCPMultiplexerType = "httpconnect"
- )
- var _ ProxyConfigurer = &TCPMuxProxyConfig{}
- type TCPMuxProxyConfig struct {
- ProxyBaseConfig
- DomainConfig
- HTTPUser string `json:"httpUser,omitempty"`
- HTTPPassword string `json:"httpPassword,omitempty"`
- RouteByHTTPUser string `json:"routeByHTTPUser,omitempty"`
- Multiplexer string `json:"multiplexer,omitempty"`
- }
- func (c *TCPMuxProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.CustomDomains = c.CustomDomains
- m.SubDomain = c.SubDomain
- m.Multiplexer = c.Multiplexer
- m.HTTPUser = c.HTTPUser
- m.HTTPPwd = c.HTTPPassword
- m.RouteByHTTPUser = c.RouteByHTTPUser
- }
- func (c *TCPMuxProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.CustomDomains = m.CustomDomains
- c.SubDomain = m.SubDomain
- c.Multiplexer = m.Multiplexer
- c.HTTPUser = m.HTTPUser
- c.HTTPPassword = m.HTTPPwd
- c.RouteByHTTPUser = m.RouteByHTTPUser
- }
- var _ ProxyConfigurer = &STCPProxyConfig{}
- type STCPProxyConfig struct {
- ProxyBaseConfig
- Secretkey string `json:"secretKey,omitempty"`
- AllowUsers []string `json:"allowUsers,omitempty"`
- }
- func (c *STCPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.Sk = c.Secretkey
- m.AllowUsers = c.AllowUsers
- }
- func (c *STCPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.Secretkey = m.Sk
- c.AllowUsers = m.AllowUsers
- }
- var _ ProxyConfigurer = &XTCPProxyConfig{}
- type XTCPProxyConfig struct {
- ProxyBaseConfig
- Secretkey string `json:"secretKey,omitempty"`
- AllowUsers []string `json:"allowUsers,omitempty"`
- }
- func (c *XTCPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.Sk = c.Secretkey
- m.AllowUsers = c.AllowUsers
- }
- func (c *XTCPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.Secretkey = m.Sk
- c.AllowUsers = m.AllowUsers
- }
- var _ ProxyConfigurer = &SUDPProxyConfig{}
- type SUDPProxyConfig struct {
- ProxyBaseConfig
- Secretkey string `json:"secretKey,omitempty"`
- AllowUsers []string `json:"allowUsers,omitempty"`
- }
- func (c *SUDPProxyConfig) MarshalToMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.MarshalToMsg(m)
- m.Sk = c.Secretkey
- m.AllowUsers = c.AllowUsers
- }
- func (c *SUDPProxyConfig) UnmarshalFromMsg(m *msg.NewProxy) {
- c.ProxyBaseConfig.UnmarshalFromMsg(m)
- c.Secretkey = m.Sk
- c.AllowUsers = m.AllowUsers
- }
|