// Copyright 2016 fatedier, fatedier@gmail.com // // 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 config import ( "fmt" "net" "reflect" "strconv" "strings" "gopkg.in/ini.v1" "github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/msg" ) // Proxy var ( proxyConfTypeMap = map[string]reflect.Type{ consts.TCPProxy: reflect.TypeOf(TCPProxyConf{}), consts.TCPMuxProxy: reflect.TypeOf(TCPMuxProxyConf{}), consts.UDPProxy: reflect.TypeOf(UDPProxyConf{}), consts.HTTPProxy: reflect.TypeOf(HTTPProxyConf{}), consts.HTTPSProxy: reflect.TypeOf(HTTPSProxyConf{}), consts.STCPProxy: reflect.TypeOf(STCPProxyConf{}), consts.XTCPProxy: reflect.TypeOf(XTCPProxyConf{}), consts.SUDPProxy: reflect.TypeOf(SUDPProxyConf{}), } ) func NewConfByType(proxyType string) ProxyConf { v, ok := proxyConfTypeMap[proxyType] if !ok { return nil } cfg := reflect.New(v).Interface().(ProxyConf) return cfg } type ProxyConf interface { GetBaseInfo() *BaseProxyConf UnmarshalFromMsg(*msg.NewProxy) UnmarshalFromIni(string, string, *ini.Section) error MarshalToMsg(*msg.NewProxy) CheckForCli() error CheckForSvr(ServerCommonConf) error Compare(ProxyConf) bool } // LocalSvrConf configures what location the client will to, or what // plugin will be used. type LocalSvrConf struct { // LocalIP specifies the IP address or host name to to. LocalIP string `ini:"local_ip" json:"local_ip"` // LocalPort specifies the port to to. LocalPort int `ini:"local_port" json:"local_port"` // Plugin specifies what plugin should be used for ng. If this value // is set, the LocalIp and LocalPort values will be ignored. By default, // this value is "". Plugin string `ini:"plugin" json:"plugin"` // PluginParams specify parameters to be passed to the plugin, if one is // being used. By default, this value is an empty map. PluginParams map[string]string `ini:"-"` } // HealthCheckConf configures health checking. This can be useful for load // balancing purposes to detect and remove proxies to failing services. type HealthCheckConf struct { // HealthCheckType specifies what protocol to use for health checking. // Valid values include "tcp", "http", and "". If this value is "", health // checking will not be performed. By default, this value is "". // // 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. HealthCheckType string `ini:"health_check_type" json:"health_check_type"` // tcp | http // HealthCheckTimeoutS 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. HealthCheckTimeoutS int `ini:"health_check_timeout_s" json:"health_check_timeout_s"` // HealthCheckMaxFailed specifies the number of allowed failures before the // is stopped. By default, this value is 1. HealthCheckMaxFailed int `ini:"health_check_max_failed" json:"health_check_max_failed"` // HealthCheckIntervalS specifies the time in seconds between health // checks. By default, this value is 10. HealthCheckIntervalS int `ini:"health_check_interval_s" json:"health_check_interval_s"` // HealthCheckURL specifies the address to send health checks to if the // health check type is "http". HealthCheckURL string `ini:"health_check_url" json:"health_check_url"` // HealthCheckAddr specifies the address to connect to if the health check // type is "tcp". HealthCheckAddr string `ini:"-"` } // BaseProxyConf provides configuration info that is common to all types. type BaseProxyConf struct { // ProxyName is the name of this ProxyName string `ini:"name" json:"name"` // ProxyType specifies the type of this Valid values include "tcp", // "udp", "http", "https", "stcp", and "xtcp". By default, this value is // "tcp". ProxyType string `ini:"type" json:"type"` // 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. By default, this value is false. UseEncryption bool `ini:"use_encryption" json:"use_encryption"` // UseCompression controls whether or not communication with the server // will be compressed. By default, this value is false. UseCompression bool `ini:"use_compression" json:"use_compression"` // 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. By default, this value is "". Group string `ini:"group" json:"group"` // GroupKey specifies a group key, which should be the same among proxies // of the same group. By default, this value is "". GroupKey string `ini:"group_key" json:"group_key"` // 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 `ini:"proxy_protocol_version" json:"proxy_protocol_version"` // BandwidthLimit limit the bandwidth // 0 means no limit BandwidthLimit BandwidthQuantity `ini:"bandwidth_limit" json:"bandwidth_limit"` // 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 `ini:"bandwidth_limit_mode" json:"bandwidth_limit_mode"` // meta info for each proxy Metas map[string]string `ini:"-" json:"metas"` LocalSvrConf `ini:",extends"` HealthCheckConf `ini:",extends"` } type DomainConf struct { CustomDomains []string `ini:"custom_domains" json:"custom_domains"` SubDomain string `ini:"subdomain" json:"subdomain"` } // HTTP type HTTPProxyConf struct { BaseProxyConf `ini:",extends"` DomainConf `ini:",extends"` Locations []string `ini:"locations" json:"locations"` HTTPUser string `ini:"http_user" json:"http_user"` HTTPPwd string `ini:"http_pwd" json:"http_pwd"` HostHeaderRewrite string `ini:"host_header_rewrite" json:"host_header_rewrite"` Headers map[string]string `ini:"-" json:"headers"` RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"` } // HTTPS type HTTPSProxyConf struct { BaseProxyConf `ini:",extends"` DomainConf `ini:",extends"` } // TCP type TCPProxyConf struct { BaseProxyConf `ini:",extends"` RemotePort int `ini:"remote_port" json:"remote_port"` } // TCPMux type TCPMuxProxyConf struct { BaseProxyConf `ini:",extends"` DomainConf `ini:",extends"` HTTPUser string `ini:"http_user" json:"http_user,omitempty"` HTTPPwd string `ini:"http_pwd" json:"http_pwd,omitempty"` RouteByHTTPUser string `ini:"route_by_http_user" json:"route_by_http_user"` Multiplexer string `ini:"multiplexer"` } // STCP type STCPProxyConf struct { BaseProxyConf `ini:",extends"` Role string `ini:"role" json:"role"` Sk string `ini:"sk" json:"sk"` } // XTCP type XTCPProxyConf struct { BaseProxyConf `ini:",extends"` Role string `ini:"role" json:"role"` Sk string `ini:"sk" json:"sk"` } // UDP type UDPProxyConf struct { BaseProxyConf `ini:",extends"` RemotePort int `ini:"remote_port" json:"remote_port"` } // SUDP type SUDPProxyConf struct { BaseProxyConf `ini:",extends"` Role string `ini:"role" json:"role"` Sk string `ini:"sk" json:"sk"` } // Proxy Conf Loader // DefaultProxyConf creates a empty ProxyConf object by proxyType. // If proxyType doesn't exist, return nil. func DefaultProxyConf(proxyType string) ProxyConf { var conf ProxyConf switch proxyType { case consts.TCPProxy: conf = &TCPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), } case consts.TCPMuxProxy: conf = &TCPMuxProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), } case consts.UDPProxy: conf = &UDPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), } case consts.HTTPProxy: conf = &HTTPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), } case consts.HTTPSProxy: conf = &HTTPSProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), } case consts.STCPProxy: conf = &STCPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), Role: "server", } case consts.XTCPProxy: conf = &XTCPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), Role: "server", } case consts.SUDPProxy: conf = &SUDPProxyConf{ BaseProxyConf: defaultBaseProxyConf(proxyType), Role: "server", } default: return nil } return conf } // Proxy loaded from ini func NewProxyConfFromIni(prefix, name string, section *ini.Section) (ProxyConf, error) { // section.Key: if key not exists, section will set it with default value. proxyType := section.Key("type").String() if proxyType == "" { proxyType = consts.TCPProxy } conf := DefaultProxyConf(proxyType) if conf == nil { return nil, fmt.Errorf("proxy %s has invalid type [%s]", name, proxyType) } if err := conf.UnmarshalFromIni(prefix, name, section); err != nil { return nil, err } if err := conf.CheckForCli(); err != nil { return nil, err } return conf, nil } // Proxy loaded from msg func NewProxyConfFromMsg(pMsg *msg.NewProxy, serverCfg ServerCommonConf) (ProxyConf, error) { if pMsg.ProxyType == "" { pMsg.ProxyType = consts.TCPProxy } conf := DefaultProxyConf(pMsg.ProxyType) if conf == nil { return nil, fmt.Errorf("proxy [%s] type [%s] error", pMsg.ProxyName, pMsg.ProxyType) } conf.UnmarshalFromMsg(pMsg) err := conf.CheckForSvr(serverCfg) if err != nil { return nil, err } return conf, nil } // Base func defaultBaseProxyConf(proxyType string) BaseProxyConf { return BaseProxyConf{ ProxyType: proxyType, LocalSvrConf: LocalSvrConf{ LocalIP: "127.0.0.1", }, BandwidthLimitMode: BandwidthLimitModeClient, } } func (cfg *BaseProxyConf) GetBaseInfo() *BaseProxyConf { return cfg } func (cfg *BaseProxyConf) compare(cmp *BaseProxyConf) bool { if cfg.ProxyName != cmp.ProxyName || cfg.ProxyType != cmp.ProxyType || cfg.UseEncryption != cmp.UseEncryption || cfg.UseCompression != cmp.UseCompression || cfg.Group != cmp.Group || cfg.GroupKey != cmp.GroupKey || cfg.ProxyProtocolVersion != cmp.ProxyProtocolVersion || !cfg.BandwidthLimit.Equal(&cmp.BandwidthLimit) || cfg.BandwidthLimitMode != cmp.BandwidthLimitMode || !reflect.DeepEqual(cfg.Metas, cmp.Metas) { return false } if !reflect.DeepEqual(cfg.LocalSvrConf, cmp.LocalSvrConf) { return false } if !reflect.DeepEqual(cfg.HealthCheckConf, cmp.HealthCheckConf) { return false } return true } // BaseProxyConf apply custom logic changes. func (cfg *BaseProxyConf) decorate(prefix string, name string, section *ini.Section) error { // proxy_name cfg.ProxyName = prefix + name // metas_xxx cfg.Metas = GetMapWithoutPrefix(section.KeysHash(), "meta_") // bandwidth_limit if bandwidth, err := section.GetKey("bandwidth_limit"); err == nil { cfg.BandwidthLimit, err = NewBandwidthQuantity(bandwidth.String()) if err != nil { return err } } // plugin_xxx cfg.LocalSvrConf.PluginParams = GetMapByPrefix(section.KeysHash(), "plugin_") // custom logic code if cfg.HealthCheckType == "tcp" && cfg.Plugin == "" { cfg.HealthCheckAddr = cfg.LocalIP + fmt.Sprintf(":%d", cfg.LocalPort) } if cfg.HealthCheckType == "http" && cfg.Plugin == "" && cfg.HealthCheckURL != "" { s := "http://" + net.JoinHostPort(cfg.LocalIP, strconv.Itoa(cfg.LocalPort)) if !strings.HasPrefix(cfg.HealthCheckURL, "/") { s += "/" } cfg.HealthCheckURL = s + cfg.HealthCheckURL } return nil } func (cfg *BaseProxyConf) marshalToMsg(pMsg *msg.NewProxy) { pMsg.ProxyName = cfg.ProxyName pMsg.ProxyType = cfg.ProxyType pMsg.UseEncryption = cfg.UseEncryption pMsg.UseCompression = cfg.UseCompression pMsg.BandwidthLimit = cfg.BandwidthLimit.String() // leave it empty for default value to reduce traffic if cfg.BandwidthLimitMode != "client" { pMsg.BandwidthLimitMode = cfg.BandwidthLimitMode } pMsg.Group = cfg.Group pMsg.GroupKey = cfg.GroupKey pMsg.Metas = cfg.Metas } func (cfg *BaseProxyConf) unmarshalFromMsg(pMsg *msg.NewProxy) { cfg.ProxyName = pMsg.ProxyName cfg.ProxyType = pMsg.ProxyType cfg.UseEncryption = pMsg.UseEncryption cfg.UseCompression = pMsg.UseCompression if pMsg.BandwidthLimit != "" { cfg.BandwidthLimit, _ = NewBandwidthQuantity(pMsg.BandwidthLimit) } if pMsg.BandwidthLimitMode != "" { cfg.BandwidthLimitMode = pMsg.BandwidthLimitMode } cfg.Group = pMsg.Group cfg.GroupKey = pMsg.GroupKey cfg.Metas = pMsg.Metas } func (cfg *BaseProxyConf) checkForCli() (err error) { if cfg.ProxyProtocolVersion != "" { if cfg.ProxyProtocolVersion != "v1" && cfg.ProxyProtocolVersion != "v2" { return fmt.Errorf("no support proxy protocol version: %s", cfg.ProxyProtocolVersion) } } if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" { return fmt.Errorf("bandwidth_limit_mode should be client or server") } if err = cfg.LocalSvrConf.checkForCli(); err != nil { return } if err = cfg.HealthCheckConf.checkForCli(); err != nil { return } return nil } func (cfg *BaseProxyConf) checkForSvr() (err error) { if cfg.BandwidthLimitMode != "client" && cfg.BandwidthLimitMode != "server" { return fmt.Errorf("bandwidth_limit_mode should be client or server") } return nil } // DomainConf func (cfg *DomainConf) check() (err error) { if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" { err = fmt.Errorf("custom_domains and subdomain should set at least one of them") return } return } func (cfg *DomainConf) checkForCli() (err error) { if err = cfg.check(); err != nil { return } return } func (cfg *DomainConf) checkForSvr(serverCfg ServerCommonConf) (err error) { if err = cfg.check(); err != nil { return } for _, domain := range cfg.CustomDomains { if serverCfg.SubDomainHost != "" && len(strings.Split(serverCfg.SubDomainHost, ".")) < len(strings.Split(domain, ".")) { if strings.Contains(domain, serverCfg.SubDomainHost) { return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, serverCfg.SubDomainHost) } } } if cfg.SubDomain != "" { if serverCfg.SubDomainHost == "" { return fmt.Errorf("subdomain is not supported because this feature is not enabled in remote frps") } if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") { return fmt.Errorf("'.' and '*' is not supported in subdomain") } } return nil } // LocalSvrConf func (cfg *LocalSvrConf) checkForCli() (err error) { if cfg.Plugin == "" { if cfg.LocalIP == "" { err = fmt.Errorf("local ip or plugin is required") return } if cfg.LocalPort <= 0 { err = fmt.Errorf("error local_port") return } } return } // HealthCheckConf func (cfg *HealthCheckConf) checkForCli() error { if cfg.HealthCheckType != "" && cfg.HealthCheckType != "tcp" && cfg.HealthCheckType != "http" { return fmt.Errorf("unsupport health check type") } if cfg.HealthCheckType != "" { if cfg.HealthCheckType == "http" && cfg.HealthCheckURL == "" { return fmt.Errorf("health_check_url is required for health check type 'http'") } } return nil } func preUnmarshalFromIni(cfg ProxyConf, prefix string, name string, section *ini.Section) error { err := section.MapTo(cfg) if err != nil { return err } err = cfg.GetBaseInfo().decorate(prefix, name, section) if err != nil { return err } return nil } // TCP func (cfg *TCPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*TCPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if cfg.RemotePort != cmpConf.RemotePort { return false } return true } func (cfg *TCPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.RemotePort = pMsg.RemotePort } func (cfg *TCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists return nil } func (cfg *TCPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.RemotePort = cfg.RemotePort } func (cfg *TCPProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists return } func (cfg *TCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } return nil } // TCPMux func (cfg *TCPMuxProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*TCPMuxProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if !reflect.DeepEqual(cfg.DomainConf, cmpConf.DomainConf) { return false } if cfg.Multiplexer != cmpConf.Multiplexer || cfg.HTTPUser != cmpConf.HTTPUser || cfg.HTTPPwd != cmpConf.HTTPPwd || cfg.RouteByHTTPUser != cmpConf.RouteByHTTPUser { return false } return true } func (cfg *TCPMuxProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists return nil } func (cfg *TCPMuxProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.CustomDomains = pMsg.CustomDomains cfg.SubDomain = pMsg.SubDomain cfg.Multiplexer = pMsg.Multiplexer cfg.HTTPUser = pMsg.HTTPUser cfg.HTTPPwd = pMsg.HTTPPwd cfg.RouteByHTTPUser = pMsg.RouteByHTTPUser } func (cfg *TCPMuxProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.CustomDomains = cfg.CustomDomains pMsg.SubDomain = cfg.SubDomain pMsg.Multiplexer = cfg.Multiplexer pMsg.HTTPUser = cfg.HTTPUser pMsg.HTTPPwd = cfg.HTTPPwd pMsg.RouteByHTTPUser = cfg.RouteByHTTPUser } func (cfg *TCPMuxProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists if err = cfg.DomainConf.checkForCli(); err != nil { return } if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer { return fmt.Errorf("parse conf error: incorrect multiplexer [%s]", cfg.Multiplexer) } return } func (cfg *TCPMuxProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } if cfg.Multiplexer != consts.HTTPConnectTCPMultiplexer { return fmt.Errorf("proxy [%s] incorrect multiplexer [%s]", cfg.ProxyName, cfg.Multiplexer) } if cfg.Multiplexer == consts.HTTPConnectTCPMultiplexer && serverCfg.TCPMuxHTTPConnectPort == 0 { return fmt.Errorf("proxy [%s] type [tcpmux] with multiplexer [httpconnect] requires tcpmux_httpconnect_port configuration", cfg.ProxyName) } if err = cfg.DomainConf.checkForSvr(serverCfg); err != nil { err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err) return } return } // UDP func (cfg *UDPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*UDPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if cfg.RemotePort != cmpConf.RemotePort { return false } return true } func (cfg *UDPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists return nil } func (cfg *UDPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.RemotePort = pMsg.RemotePort } func (cfg *UDPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.RemotePort = cfg.RemotePort } func (cfg *UDPProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists return } func (cfg *UDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } return nil } // HTTP func (cfg *HTTPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*HTTPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if !reflect.DeepEqual(cfg.DomainConf, cmpConf.DomainConf) { return false } if !reflect.DeepEqual(cfg.Locations, cmpConf.Locations) || cfg.HTTPUser != cmpConf.HTTPUser || cfg.HTTPPwd != cmpConf.HTTPPwd || cfg.HostHeaderRewrite != cmpConf.HostHeaderRewrite || cfg.RouteByHTTPUser != cmpConf.RouteByHTTPUser || !reflect.DeepEqual(cfg.Headers, cmpConf.Headers) { return false } return true } func (cfg *HTTPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists cfg.Headers = GetMapWithoutPrefix(section.KeysHash(), "header_") return nil } func (cfg *HTTPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.CustomDomains = pMsg.CustomDomains cfg.SubDomain = pMsg.SubDomain cfg.Locations = pMsg.Locations cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite cfg.HTTPUser = pMsg.HTTPUser cfg.HTTPPwd = pMsg.HTTPPwd cfg.Headers = pMsg.Headers cfg.RouteByHTTPUser = pMsg.RouteByHTTPUser } func (cfg *HTTPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.CustomDomains = cfg.CustomDomains pMsg.SubDomain = cfg.SubDomain pMsg.Locations = cfg.Locations pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite pMsg.HTTPUser = cfg.HTTPUser pMsg.HTTPPwd = cfg.HTTPPwd pMsg.Headers = cfg.Headers pMsg.RouteByHTTPUser = cfg.RouteByHTTPUser } func (cfg *HTTPProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists if err = cfg.DomainConf.checkForCli(); err != nil { return } return } func (cfg *HTTPProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } if serverCfg.VhostHTTPPort == 0 { return fmt.Errorf("type [http] not support when vhost_http_port is not set") } if err = cfg.DomainConf.checkForSvr(serverCfg); err != nil { err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err) return } return } // HTTPS func (cfg *HTTPSProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*HTTPSProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if !reflect.DeepEqual(cfg.DomainConf, cmpConf.DomainConf) { return false } return true } func (cfg *HTTPSProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists return nil } func (cfg *HTTPSProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.CustomDomains = pMsg.CustomDomains cfg.SubDomain = pMsg.SubDomain } func (cfg *HTTPSProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.CustomDomains = cfg.CustomDomains pMsg.SubDomain = cfg.SubDomain } func (cfg *HTTPSProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists if err = cfg.DomainConf.checkForCli(); err != nil { return } return } func (cfg *HTTPSProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } if serverCfg.VhostHTTPSPort == 0 { return fmt.Errorf("type [https] not support when vhost_https_port is not set") } if err = cfg.DomainConf.checkForSvr(serverCfg); err != nil { err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err) return } return } // SUDP func (cfg *SUDPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*SUDPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if cfg.Role != cmpConf.Role || cfg.Sk != cmpConf.Sk { return false } return true } func (cfg *SUDPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists return nil } // Only for role server. func (cfg *SUDPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.Sk = pMsg.Sk } func (cfg *SUDPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.Sk = cfg.Sk } func (cfg *SUDPProxyConf) CheckForCli() (err error) { if err := cfg.BaseProxyConf.checkForCli(); err != nil { return err } // Add custom logic check if exists if cfg.Role != "server" { return fmt.Errorf("role should be 'server'") } return nil } func (cfg *SUDPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } return nil } // STCP func (cfg *STCPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*STCPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if cfg.Role != cmpConf.Role || cfg.Sk != cmpConf.Sk { return false } return true } func (cfg *STCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists if cfg.Role == "" { cfg.Role = "server" } return nil } // Only for role server. func (cfg *STCPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.Sk = pMsg.Sk } func (cfg *STCPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.Sk = cfg.Sk } func (cfg *STCPProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists if cfg.Role != "server" { return fmt.Errorf("role should be 'server'") } return } func (cfg *STCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } return nil } // XTCP func (cfg *XTCPProxyConf) Compare(cmp ProxyConf) bool { cmpConf, ok := cmp.(*XTCPProxyConf) if !ok { return false } if !cfg.BaseProxyConf.compare(&cmpConf.BaseProxyConf) { return false } // Add custom logic equal if exists. if cfg.Role != cmpConf.Role || cfg.Sk != cmpConf.Sk { return false } return true } func (cfg *XTCPProxyConf) UnmarshalFromIni(prefix string, name string, section *ini.Section) error { err := preUnmarshalFromIni(cfg, prefix, name, section) if err != nil { return err } // Add custom logic unmarshal if exists if cfg.Role == "" { cfg.Role = "server" } return nil } // Only for role server. func (cfg *XTCPProxyConf) UnmarshalFromMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.unmarshalFromMsg(pMsg) // Add custom logic unmarshal if exists cfg.Sk = pMsg.Sk } func (cfg *XTCPProxyConf) MarshalToMsg(pMsg *msg.NewProxy) { cfg.BaseProxyConf.marshalToMsg(pMsg) // Add custom logic marshal if exists pMsg.Sk = cfg.Sk } func (cfg *XTCPProxyConf) CheckForCli() (err error) { if err = cfg.BaseProxyConf.checkForCli(); err != nil { return } // Add custom logic check if exists if cfg.Role != "server" { return fmt.Errorf("role should be 'server'") } return } func (cfg *XTCPProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { if err := cfg.BaseProxyConf.checkForSvr(); err != nil { return err } return nil }