frp/pkg/config/legacy/conversion.go
Gerhard Tan 9152c59570
fix nil map error when using plugin headers in legacy format (#3996)
* fix nil map error when using plugin headers in legacy format

* create map on demand

* better initialization
2024-02-19 13:03:37 +08:00

356 lines
12 KiB
Go

// 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 legacy
import (
"strings"
"github.com/samber/lo"
"github.com/fatedier/frp/pkg/config/types"
v1 "github.com/fatedier/frp/pkg/config/v1"
)
func Convert_ClientCommonConf_To_v1(conf *ClientCommonConf) *v1.ClientCommonConfig {
out := &v1.ClientCommonConfig{}
out.User = conf.User
out.Auth.Method = v1.AuthMethod(conf.ClientConfig.AuthenticationMethod)
out.Auth.Token = conf.ClientConfig.Token
if conf.ClientConfig.AuthenticateHeartBeats {
out.Auth.AdditionalScopes = append(out.Auth.AdditionalScopes, v1.AuthScopeHeartBeats)
}
if conf.ClientConfig.AuthenticateNewWorkConns {
out.Auth.AdditionalScopes = append(out.Auth.AdditionalScopes, v1.AuthScopeNewWorkConns)
}
out.Auth.OIDC.ClientID = conf.ClientConfig.OidcClientID
out.Auth.OIDC.ClientSecret = conf.ClientConfig.OidcClientSecret
out.Auth.OIDC.Audience = conf.ClientConfig.OidcAudience
out.Auth.OIDC.Scope = conf.ClientConfig.OidcScope
out.Auth.OIDC.TokenEndpointURL = conf.ClientConfig.OidcTokenEndpointURL
out.Auth.OIDC.AdditionalEndpointParams = conf.ClientConfig.OidcAdditionalEndpointParams
out.ServerAddr = conf.ServerAddr
out.ServerPort = conf.ServerPort
out.NatHoleSTUNServer = conf.NatHoleSTUNServer
out.Transport.DialServerTimeout = conf.DialServerTimeout
out.Transport.DialServerKeepAlive = conf.DialServerKeepAlive
out.Transport.ConnectServerLocalIP = conf.ConnectServerLocalIP
out.Transport.ProxyURL = conf.HTTPProxy
out.Transport.PoolCount = conf.PoolCount
out.Transport.TCPMux = lo.ToPtr(conf.TCPMux)
out.Transport.TCPMuxKeepaliveInterval = conf.TCPMuxKeepaliveInterval
out.Transport.Protocol = conf.Protocol
out.Transport.HeartbeatInterval = conf.HeartbeatInterval
out.Transport.HeartbeatTimeout = conf.HeartbeatTimeout
out.Transport.QUIC.KeepalivePeriod = conf.QUICKeepalivePeriod
out.Transport.QUIC.MaxIdleTimeout = conf.QUICMaxIdleTimeout
out.Transport.QUIC.MaxIncomingStreams = conf.QUICMaxIncomingStreams
out.Transport.TLS.Enable = lo.ToPtr(conf.TLSEnable)
out.Transport.TLS.DisableCustomTLSFirstByte = lo.ToPtr(conf.DisableCustomTLSFirstByte)
out.Transport.TLS.TLSConfig.CertFile = conf.TLSCertFile
out.Transport.TLS.TLSConfig.KeyFile = conf.TLSKeyFile
out.Transport.TLS.TLSConfig.TrustedCaFile = conf.TLSTrustedCaFile
out.Transport.TLS.TLSConfig.ServerName = conf.TLSServerName
out.Log.To = conf.LogFile
out.Log.Level = conf.LogLevel
out.Log.MaxDays = conf.LogMaxDays
out.Log.DisablePrintColor = conf.DisableLogColor
out.WebServer.Addr = conf.AdminAddr
out.WebServer.Port = conf.AdminPort
out.WebServer.User = conf.AdminUser
out.WebServer.Password = conf.AdminPwd
out.WebServer.AssetsDir = conf.AssetsDir
out.WebServer.PprofEnable = conf.PprofEnable
out.DNSServer = conf.DNSServer
out.LoginFailExit = lo.ToPtr(conf.LoginFailExit)
out.Start = conf.Start
out.UDPPacketSize = conf.UDPPacketSize
out.Metadatas = conf.Metas
out.IncludeConfigFiles = conf.IncludeConfigFiles
return out
}
func Convert_ServerCommonConf_To_v1(conf *ServerCommonConf) *v1.ServerConfig {
out := &v1.ServerConfig{}
out.Auth.Method = v1.AuthMethod(conf.ServerConfig.AuthenticationMethod)
out.Auth.Token = conf.ServerConfig.Token
if conf.ServerConfig.AuthenticateHeartBeats {
out.Auth.AdditionalScopes = append(out.Auth.AdditionalScopes, v1.AuthScopeHeartBeats)
}
if conf.ServerConfig.AuthenticateNewWorkConns {
out.Auth.AdditionalScopes = append(out.Auth.AdditionalScopes, v1.AuthScopeNewWorkConns)
}
out.Auth.OIDC.Audience = conf.ServerConfig.OidcAudience
out.Auth.OIDC.Issuer = conf.ServerConfig.OidcIssuer
out.Auth.OIDC.SkipExpiryCheck = conf.ServerConfig.OidcSkipExpiryCheck
out.Auth.OIDC.SkipIssuerCheck = conf.ServerConfig.OidcSkipIssuerCheck
out.BindAddr = conf.BindAddr
out.BindPort = conf.BindPort
out.KCPBindPort = conf.KCPBindPort
out.QUICBindPort = conf.QUICBindPort
out.Transport.QUIC.KeepalivePeriod = conf.QUICKeepalivePeriod
out.Transport.QUIC.MaxIdleTimeout = conf.QUICMaxIdleTimeout
out.Transport.QUIC.MaxIncomingStreams = conf.QUICMaxIncomingStreams
out.ProxyBindAddr = conf.ProxyBindAddr
out.VhostHTTPPort = conf.VhostHTTPPort
out.VhostHTTPSPort = conf.VhostHTTPSPort
out.TCPMuxHTTPConnectPort = conf.TCPMuxHTTPConnectPort
out.TCPMuxPassthrough = conf.TCPMuxPassthrough
out.VhostHTTPTimeout = conf.VhostHTTPTimeout
out.WebServer.Addr = conf.DashboardAddr
out.WebServer.Port = conf.DashboardPort
out.WebServer.User = conf.DashboardUser
out.WebServer.Password = conf.DashboardPwd
out.WebServer.AssetsDir = conf.AssetsDir
if conf.DashboardTLSMode {
out.WebServer.TLS = &v1.TLSConfig{}
out.WebServer.TLS.CertFile = conf.DashboardTLSCertFile
out.WebServer.TLS.KeyFile = conf.DashboardTLSKeyFile
out.WebServer.PprofEnable = conf.PprofEnable
}
out.EnablePrometheus = conf.EnablePrometheus
out.Log.To = conf.LogFile
out.Log.Level = conf.LogLevel
out.Log.MaxDays = conf.LogMaxDays
out.Log.DisablePrintColor = conf.DisableLogColor
out.DetailedErrorsToClient = lo.ToPtr(conf.DetailedErrorsToClient)
out.SubDomainHost = conf.SubDomainHost
out.Custom404Page = conf.Custom404Page
out.UserConnTimeout = conf.UserConnTimeout
out.UDPPacketSize = conf.UDPPacketSize
out.NatHoleAnalysisDataReserveHours = conf.NatHoleAnalysisDataReserveHours
out.Transport.TCPMux = lo.ToPtr(conf.TCPMux)
out.Transport.TCPMuxKeepaliveInterval = conf.TCPMuxKeepaliveInterval
out.Transport.TCPKeepAlive = conf.TCPKeepAlive
out.Transport.MaxPoolCount = conf.MaxPoolCount
out.Transport.HeartbeatTimeout = conf.HeartbeatTimeout
out.Transport.TLS.Force = conf.TLSOnly
out.Transport.TLS.CertFile = conf.TLSCertFile
out.Transport.TLS.KeyFile = conf.TLSKeyFile
out.Transport.TLS.TrustedCaFile = conf.TLSTrustedCaFile
out.MaxPortsPerClient = conf.MaxPortsPerClient
for _, v := range conf.HTTPPlugins {
out.HTTPPlugins = append(out.HTTPPlugins, v1.HTTPPluginOptions{
Name: v.Name,
Addr: v.Addr,
Path: v.Path,
Ops: v.Ops,
TLSVerify: v.TLSVerify,
})
}
out.AllowPorts, _ = types.NewPortsRangeSliceFromString(conf.AllowPortsStr)
return out
}
func transformHeadersFromPluginParams(params map[string]string) v1.HeaderOperations {
out := v1.HeaderOperations{}
for k, v := range params {
if !strings.HasPrefix(k, "plugin_header_") {
continue
}
if k = strings.TrimPrefix(k, "plugin_header_"); k != "" {
if out.Set == nil {
out.Set = make(map[string]string)
}
out.Set[k] = v
}
}
return out
}
func Convert_ProxyConf_To_v1_Base(conf ProxyConf) *v1.ProxyBaseConfig {
out := &v1.ProxyBaseConfig{}
base := conf.GetBaseConfig()
out.Name = base.ProxyName
out.Type = base.ProxyType
out.Metadatas = base.Metas
out.Transport.UseEncryption = base.UseEncryption
out.Transport.UseCompression = base.UseCompression
out.Transport.BandwidthLimit = base.BandwidthLimit
out.Transport.BandwidthLimitMode = base.BandwidthLimitMode
out.Transport.ProxyProtocolVersion = base.ProxyProtocolVersion
out.LoadBalancer.Group = base.Group
out.LoadBalancer.GroupKey = base.GroupKey
out.HealthCheck.Type = base.HealthCheckType
out.HealthCheck.TimeoutSeconds = base.HealthCheckTimeoutS
out.HealthCheck.MaxFailed = base.HealthCheckMaxFailed
out.HealthCheck.IntervalSeconds = base.HealthCheckIntervalS
out.HealthCheck.Path = base.HealthCheckURL
out.LocalIP = base.LocalIP
out.LocalPort = base.LocalPort
switch base.Plugin {
case "http2https":
out.Plugin.ClientPluginOptions = &v1.HTTP2HTTPSPluginOptions{
LocalAddr: base.PluginParams["plugin_local_addr"],
HostHeaderRewrite: base.PluginParams["plugin_host_header_rewrite"],
RequestHeaders: transformHeadersFromPluginParams(base.PluginParams),
}
case "http_proxy":
out.Plugin.ClientPluginOptions = &v1.HTTPProxyPluginOptions{
HTTPUser: base.PluginParams["plugin_http_user"],
HTTPPassword: base.PluginParams["plugin_http_passwd"],
}
case "https2http":
out.Plugin.ClientPluginOptions = &v1.HTTPS2HTTPPluginOptions{
LocalAddr: base.PluginParams["plugin_local_addr"],
HostHeaderRewrite: base.PluginParams["plugin_host_header_rewrite"],
RequestHeaders: transformHeadersFromPluginParams(base.PluginParams),
CrtPath: base.PluginParams["plugin_crt_path"],
KeyPath: base.PluginParams["plugin_key_path"],
}
case "https2https":
out.Plugin.ClientPluginOptions = &v1.HTTPS2HTTPSPluginOptions{
LocalAddr: base.PluginParams["plugin_local_addr"],
HostHeaderRewrite: base.PluginParams["plugin_host_header_rewrite"],
RequestHeaders: transformHeadersFromPluginParams(base.PluginParams),
CrtPath: base.PluginParams["plugin_crt_path"],
KeyPath: base.PluginParams["plugin_key_path"],
}
case "socks5":
out.Plugin.ClientPluginOptions = &v1.Socks5PluginOptions{
Username: base.PluginParams["plugin_user"],
Password: base.PluginParams["plugin_passwd"],
}
case "static_file":
out.Plugin.ClientPluginOptions = &v1.StaticFilePluginOptions{
LocalPath: base.PluginParams["plugin_local_path"],
StripPrefix: base.PluginParams["plugin_strip_prefix"],
HTTPUser: base.PluginParams["plugin_http_user"],
HTTPPassword: base.PluginParams["plugin_http_passwd"],
}
case "unix_domain_socket":
out.Plugin.ClientPluginOptions = &v1.UnixDomainSocketPluginOptions{
UnixPath: base.PluginParams["plugin_unix_path"],
}
}
out.Plugin.Type = base.Plugin
return out
}
func Convert_ProxyConf_To_v1(conf ProxyConf) v1.ProxyConfigurer {
outBase := Convert_ProxyConf_To_v1_Base(conf)
var out v1.ProxyConfigurer
switch v := conf.(type) {
case *TCPProxyConf:
c := &v1.TCPProxyConfig{ProxyBaseConfig: *outBase}
c.RemotePort = v.RemotePort
out = c
case *UDPProxyConf:
c := &v1.UDPProxyConfig{ProxyBaseConfig: *outBase}
c.RemotePort = v.RemotePort
out = c
case *HTTPProxyConf:
c := &v1.HTTPProxyConfig{ProxyBaseConfig: *outBase}
c.CustomDomains = v.CustomDomains
c.SubDomain = v.SubDomain
c.Locations = v.Locations
c.HTTPUser = v.HTTPUser
c.HTTPPassword = v.HTTPPwd
c.HostHeaderRewrite = v.HostHeaderRewrite
c.RequestHeaders.Set = v.Headers
c.RouteByHTTPUser = v.RouteByHTTPUser
out = c
case *HTTPSProxyConf:
c := &v1.HTTPSProxyConfig{ProxyBaseConfig: *outBase}
c.CustomDomains = v.CustomDomains
c.SubDomain = v.SubDomain
out = c
case *TCPMuxProxyConf:
c := &v1.TCPMuxProxyConfig{ProxyBaseConfig: *outBase}
c.CustomDomains = v.CustomDomains
c.SubDomain = v.SubDomain
c.HTTPUser = v.HTTPUser
c.HTTPPassword = v.HTTPPwd
c.RouteByHTTPUser = v.RouteByHTTPUser
c.Multiplexer = v.Multiplexer
out = c
case *STCPProxyConf:
c := &v1.STCPProxyConfig{ProxyBaseConfig: *outBase}
c.Secretkey = v.Sk
c.AllowUsers = v.AllowUsers
out = c
case *SUDPProxyConf:
c := &v1.SUDPProxyConfig{ProxyBaseConfig: *outBase}
c.Secretkey = v.Sk
c.AllowUsers = v.AllowUsers
out = c
case *XTCPProxyConf:
c := &v1.XTCPProxyConfig{ProxyBaseConfig: *outBase}
c.Secretkey = v.Sk
c.AllowUsers = v.AllowUsers
out = c
}
return out
}
func Convert_VisitorConf_To_v1_Base(conf VisitorConf) *v1.VisitorBaseConfig {
out := &v1.VisitorBaseConfig{}
base := conf.GetBaseConfig()
out.Name = base.ProxyName
out.Type = base.ProxyType
out.Transport.UseEncryption = base.UseEncryption
out.Transport.UseCompression = base.UseCompression
out.SecretKey = base.Sk
out.ServerUser = base.ServerUser
out.ServerName = base.ServerName
out.BindAddr = base.BindAddr
out.BindPort = base.BindPort
return out
}
func Convert_VisitorConf_To_v1(conf VisitorConf) v1.VisitorConfigurer {
outBase := Convert_VisitorConf_To_v1_Base(conf)
var out v1.VisitorConfigurer
switch v := conf.(type) {
case *STCPVisitorConf:
c := &v1.STCPVisitorConfig{VisitorBaseConfig: *outBase}
out = c
case *SUDPVisitorConf:
c := &v1.SUDPVisitorConfig{VisitorBaseConfig: *outBase}
out = c
case *XTCPVisitorConf:
c := &v1.XTCPVisitorConfig{VisitorBaseConfig: *outBase}
c.Protocol = v.Protocol
c.KeepTunnelOpen = v.KeepTunnelOpen
c.MaxRetriesAnHour = v.MaxRetriesAnHour
c.MinRetryInterval = v.MinRetryInterval
c.FallbackTo = v.FallbackTo
c.FallbackTimeoutMs = v.FallbackTimeoutMs
out = c
}
return out
}