mirror of
https://github.com/fatedier/frp.git
synced 2024-12-16 19:47:56 +08:00
49b503c17b
Proxy names specified in 'start' params divided by ',' will be started. If it is empty or not defined, all proxies will be started.
493 lines
12 KiB
Go
493 lines
12 KiB
Go
// 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"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/fatedier/frp/models/consts"
|
|
"github.com/fatedier/frp/models/msg"
|
|
|
|
"github.com/fatedier/frp/utils/util"
|
|
ini "github.com/vaughan0/go-ini"
|
|
)
|
|
|
|
var proxyConfTypeMap map[string]reflect.Type
|
|
|
|
func init() {
|
|
proxyConfTypeMap = make(map[string]reflect.Type)
|
|
proxyConfTypeMap[consts.TcpProxy] = reflect.TypeOf(TcpProxyConf{})
|
|
proxyConfTypeMap[consts.UdpProxy] = reflect.TypeOf(UdpProxyConf{})
|
|
proxyConfTypeMap[consts.HttpProxy] = reflect.TypeOf(HttpProxyConf{})
|
|
proxyConfTypeMap[consts.HttpsProxy] = reflect.TypeOf(HttpsProxyConf{})
|
|
}
|
|
|
|
// NewConfByType creates a empty ProxyConf object by proxyType.
|
|
// If proxyType isn't exist, return nil.
|
|
func NewConfByType(proxyType string) ProxyConf {
|
|
v, ok := proxyConfTypeMap[proxyType]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
cfg := reflect.New(v).Interface().(ProxyConf)
|
|
return cfg
|
|
}
|
|
|
|
type ProxyConf interface {
|
|
GetName() string
|
|
GetBaseInfo() *BaseProxyConf
|
|
LoadFromMsg(pMsg *msg.NewProxy)
|
|
LoadFromFile(name string, conf ini.Section) error
|
|
UnMarshalToMsg(pMsg *msg.NewProxy)
|
|
Check() error
|
|
}
|
|
|
|
func NewProxyConf(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
|
if pMsg.ProxyType == "" {
|
|
pMsg.ProxyType = consts.TcpProxy
|
|
}
|
|
|
|
cfg = NewConfByType(pMsg.ProxyType)
|
|
if cfg == nil {
|
|
err = fmt.Errorf("proxy [%s] type [%s] error", pMsg.ProxyName, pMsg.ProxyType)
|
|
return
|
|
}
|
|
cfg.LoadFromMsg(pMsg)
|
|
err = cfg.Check()
|
|
return
|
|
}
|
|
|
|
func NewProxyConfFromFile(name string, section ini.Section) (cfg ProxyConf, err error) {
|
|
proxyType := section["type"]
|
|
if proxyType == "" {
|
|
proxyType = consts.TcpProxy
|
|
section["type"] = consts.TcpProxy
|
|
}
|
|
cfg = NewConfByType(proxyType)
|
|
if cfg == nil {
|
|
err = fmt.Errorf("proxy [%s] type [%s] error", name, proxyType)
|
|
return
|
|
}
|
|
err = cfg.LoadFromFile(name, section)
|
|
return
|
|
}
|
|
|
|
// BaseProxy info
|
|
type BaseProxyConf struct {
|
|
ProxyName string `json:"proxy_name"`
|
|
ProxyType string `json:"proxy_type"`
|
|
|
|
UseEncryption bool `json:"use_encryption"`
|
|
UseCompression bool `json:"use_compression"`
|
|
}
|
|
|
|
func (cfg *BaseProxyConf) GetName() string {
|
|
return cfg.ProxyName
|
|
}
|
|
|
|
func (cfg *BaseProxyConf) GetBaseInfo() *BaseProxyConf {
|
|
return cfg
|
|
}
|
|
|
|
func (cfg *BaseProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.ProxyName = pMsg.ProxyName
|
|
cfg.ProxyType = pMsg.ProxyType
|
|
cfg.UseEncryption = pMsg.UseEncryption
|
|
cfg.UseCompression = pMsg.UseCompression
|
|
}
|
|
|
|
func (cfg *BaseProxyConf) LoadFromFile(name string, section ini.Section) error {
|
|
var (
|
|
tmpStr string
|
|
ok bool
|
|
)
|
|
if ClientCommonCfg.User != "" {
|
|
cfg.ProxyName = ClientCommonCfg.User + "." + name
|
|
} else {
|
|
cfg.ProxyName = name
|
|
}
|
|
cfg.ProxyType = section["type"]
|
|
|
|
tmpStr, ok = section["use_encryption"]
|
|
if ok && tmpStr == "true" {
|
|
cfg.UseEncryption = true
|
|
}
|
|
|
|
tmpStr, ok = section["use_compression"]
|
|
if ok && tmpStr == "true" {
|
|
cfg.UseCompression = true
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (cfg *BaseProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
pMsg.ProxyName = cfg.ProxyName
|
|
pMsg.ProxyType = cfg.ProxyType
|
|
pMsg.UseEncryption = cfg.UseEncryption
|
|
pMsg.UseCompression = cfg.UseCompression
|
|
}
|
|
|
|
// Bind info
|
|
type BindInfoConf struct {
|
|
BindAddr string `json:"bind_addr"`
|
|
RemotePort int64 `json:"remote_port"`
|
|
}
|
|
|
|
func (cfg *BindInfoConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.BindAddr = ServerCommonCfg.BindAddr
|
|
cfg.RemotePort = pMsg.RemotePort
|
|
}
|
|
|
|
func (cfg *BindInfoConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
var (
|
|
tmpStr string
|
|
ok bool
|
|
)
|
|
if tmpStr, ok = section["remote_port"]; ok {
|
|
if cfg.RemotePort, err = strconv.ParseInt(tmpStr, 10, 64); err != nil {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] remote_port error", name)
|
|
}
|
|
} else {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] remote_port not found", name)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (cfg *BindInfoConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
pMsg.RemotePort = cfg.RemotePort
|
|
}
|
|
|
|
func (cfg *BindInfoConf) check() (err error) {
|
|
if len(ServerCommonCfg.PrivilegeAllowPorts) != 0 {
|
|
if ok := util.ContainsPort(ServerCommonCfg.PrivilegeAllowPorts, cfg.RemotePort); !ok {
|
|
return fmt.Errorf("remote port [%d] isn't allowed", cfg.RemotePort)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Domain info
|
|
type DomainConf struct {
|
|
CustomDomains []string `json:"custom_domains"`
|
|
SubDomain string `json:"sub_domain"`
|
|
}
|
|
|
|
func (cfg *DomainConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.CustomDomains = pMsg.CustomDomains
|
|
cfg.SubDomain = pMsg.SubDomain
|
|
}
|
|
|
|
func (cfg *DomainConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
var (
|
|
tmpStr string
|
|
ok bool
|
|
)
|
|
if tmpStr, ok = section["custom_domains"]; ok {
|
|
cfg.CustomDomains = strings.Split(tmpStr, ",")
|
|
for i, domain := range cfg.CustomDomains {
|
|
cfg.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
|
}
|
|
}
|
|
|
|
if tmpStr, ok = section["subdomain"]; ok {
|
|
cfg.SubDomain = tmpStr
|
|
}
|
|
|
|
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them", name)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (cfg *DomainConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
pMsg.CustomDomains = cfg.CustomDomains
|
|
pMsg.SubDomain = cfg.SubDomain
|
|
}
|
|
|
|
func (cfg *DomainConf) check() (err error) {
|
|
for _, domain := range cfg.CustomDomains {
|
|
if ServerCommonCfg.SubDomainHost != "" && len(strings.Split(ServerCommonCfg.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
|
|
if strings.Contains(domain, ServerCommonCfg.SubDomainHost) {
|
|
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, ServerCommonCfg.SubDomainHost)
|
|
}
|
|
}
|
|
}
|
|
|
|
if cfg.SubDomain != "" {
|
|
if ServerCommonCfg.SubDomainHost == "" {
|
|
return fmt.Errorf("subdomain is not supported because this feature is not enabled by frps")
|
|
}
|
|
if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") {
|
|
return fmt.Errorf("'.' and '*' is not supported in subdomain")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Local service info
|
|
type LocalSvrConf struct {
|
|
LocalIp string `json:"-"`
|
|
LocalPort int `json:"-"`
|
|
}
|
|
|
|
func (cfg *LocalSvrConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
if cfg.LocalIp = section["local_ip"]; cfg.LocalIp == "" {
|
|
cfg.LocalIp = "127.0.0.1"
|
|
}
|
|
|
|
if tmpStr, ok := section["local_port"]; ok {
|
|
if cfg.LocalPort, err = strconv.Atoi(tmpStr); err != nil {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] local_port error", name)
|
|
}
|
|
} else {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] local_port not found", name)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type PluginConf struct {
|
|
Plugin string `json:"-"`
|
|
PluginParams map[string]string `json:"-"`
|
|
}
|
|
|
|
func (cfg *PluginConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
cfg.Plugin = section["plugin"]
|
|
cfg.PluginParams = make(map[string]string)
|
|
if cfg.Plugin != "" {
|
|
// get params begin with "plugin_"
|
|
for k, v := range section {
|
|
if strings.HasPrefix(k, "plugin_") {
|
|
cfg.PluginParams[k] = v
|
|
}
|
|
}
|
|
} else {
|
|
return fmt.Errorf("Parse conf error: proxy [%s] no plugin info found", name)
|
|
}
|
|
return
|
|
}
|
|
|
|
// TCP
|
|
type TcpProxyConf struct {
|
|
BaseProxyConf
|
|
BindInfoConf
|
|
|
|
LocalSvrConf
|
|
PluginConf
|
|
}
|
|
|
|
func (cfg *TcpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
|
cfg.BindInfoConf.LoadFromMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *TcpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.BindInfoConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = cfg.PluginConf.LoadFromFile(name, section); err != nil {
|
|
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (cfg *TcpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
|
cfg.BindInfoConf.UnMarshalToMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *TcpProxyConf) Check() (err error) {
|
|
err = cfg.BindInfoConf.check()
|
|
return
|
|
}
|
|
|
|
// UDP
|
|
type UdpProxyConf struct {
|
|
BaseProxyConf
|
|
BindInfoConf
|
|
|
|
LocalSvrConf
|
|
}
|
|
|
|
func (cfg *UdpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
|
cfg.BindInfoConf.LoadFromMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *UdpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.BindInfoConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (cfg *UdpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
|
cfg.BindInfoConf.UnMarshalToMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *UdpProxyConf) Check() (err error) {
|
|
err = cfg.BindInfoConf.check()
|
|
return
|
|
}
|
|
|
|
// HTTP
|
|
type HttpProxyConf struct {
|
|
BaseProxyConf
|
|
DomainConf
|
|
|
|
LocalSvrConf
|
|
PluginConf
|
|
|
|
Locations []string `json:"locations"`
|
|
HostHeaderRewrite string `json:"host_header_rewrite"`
|
|
HttpUser string `json:"-"`
|
|
HttpPwd string `json:"-"`
|
|
}
|
|
|
|
func (cfg *HttpProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
|
cfg.DomainConf.LoadFromMsg(pMsg)
|
|
|
|
cfg.Locations = pMsg.Locations
|
|
cfg.HostHeaderRewrite = pMsg.HostHeaderRewrite
|
|
cfg.HttpUser = pMsg.HttpUser
|
|
cfg.HttpPwd = pMsg.HttpPwd
|
|
}
|
|
|
|
func (cfg *HttpProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.DomainConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
|
|
var (
|
|
tmpStr string
|
|
ok bool
|
|
)
|
|
if tmpStr, ok = section["locations"]; ok {
|
|
cfg.Locations = strings.Split(tmpStr, ",")
|
|
} else {
|
|
cfg.Locations = []string{""}
|
|
}
|
|
|
|
cfg.HostHeaderRewrite = section["host_header_rewrite"]
|
|
cfg.HttpUser = section["http_user"]
|
|
cfg.HttpPwd = section["http_pwd"]
|
|
return
|
|
}
|
|
|
|
func (cfg *HttpProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
|
cfg.DomainConf.UnMarshalToMsg(pMsg)
|
|
|
|
pMsg.Locations = cfg.Locations
|
|
pMsg.HostHeaderRewrite = cfg.HostHeaderRewrite
|
|
pMsg.HttpUser = cfg.HttpUser
|
|
pMsg.HttpPwd = cfg.HttpPwd
|
|
}
|
|
|
|
func (cfg *HttpProxyConf) Check() (err error) {
|
|
if ServerCommonCfg.VhostHttpPort == 0 {
|
|
return fmt.Errorf("type [http] not support when vhost_http_port is not set")
|
|
}
|
|
err = cfg.DomainConf.check()
|
|
return
|
|
}
|
|
|
|
// HTTPS
|
|
type HttpsProxyConf struct {
|
|
BaseProxyConf
|
|
DomainConf
|
|
|
|
LocalSvrConf
|
|
PluginConf
|
|
}
|
|
|
|
func (cfg *HttpsProxyConf) LoadFromMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.LoadFromMsg(pMsg)
|
|
cfg.DomainConf.LoadFromMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *HttpsProxyConf) LoadFromFile(name string, section ini.Section) (err error) {
|
|
if err = cfg.BaseProxyConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.DomainConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
if err = cfg.LocalSvrConf.LoadFromFile(name, section); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func (cfg *HttpsProxyConf) UnMarshalToMsg(pMsg *msg.NewProxy) {
|
|
cfg.BaseProxyConf.UnMarshalToMsg(pMsg)
|
|
cfg.DomainConf.UnMarshalToMsg(pMsg)
|
|
}
|
|
|
|
func (cfg *HttpsProxyConf) Check() (err error) {
|
|
if ServerCommonCfg.VhostHttpsPort == 0 {
|
|
return fmt.Errorf("type [https] not support when vhost_https_port is not set")
|
|
}
|
|
err = cfg.DomainConf.check()
|
|
return
|
|
}
|
|
|
|
// if len(startProxy) is 0, start all
|
|
// otherwise just start proxies in startProxy map
|
|
func LoadProxyConfFromFile(prefix string, conf ini.File, startProxy map[string]struct{}) (proxyConfs map[string]ProxyConf, err error) {
|
|
if prefix != "" {
|
|
prefix += "."
|
|
}
|
|
|
|
startAll := true
|
|
if len(startProxy) > 0 {
|
|
startAll = false
|
|
}
|
|
proxyConfs = make(map[string]ProxyConf)
|
|
for name, section := range conf {
|
|
_, shouldStart := startProxy[name]
|
|
if name != "common" && (startAll || shouldStart) {
|
|
cfg, err := NewProxyConfFromFile(name, section)
|
|
if err != nil {
|
|
return proxyConfs, err
|
|
}
|
|
proxyConfs[prefix+name] = cfg
|
|
}
|
|
}
|
|
return
|
|
}
|