frp/src/models/server/config.go

371 lines
10 KiB
Go
Raw Normal View History

2016-03-14 03:18:24 +00:00
// 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.
2016-02-18 10:24:48 +00:00
package server
2016-01-27 13:24:36 +00:00
import (
"fmt"
"strconv"
2016-04-18 07:16:40 +00:00
"strings"
"sync"
2016-01-27 13:24:36 +00:00
ini "github.com/vaughan0/go-ini"
2016-04-18 07:16:40 +00:00
"github.com/fatedier/frp/src/models/consts"
"github.com/fatedier/frp/src/models/metric"
"github.com/fatedier/frp/src/utils/log"
"github.com/fatedier/frp/src/utils/vhost"
2016-01-27 13:24:36 +00:00
)
// common config
var (
ConfigFile string = "./frps.ini"
BindAddr string = "0.0.0.0"
BindPort int64 = 7000
VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol
VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
AssetsDir string = ""
LogFile string = "console"
LogWay string = "console" // console or file
LogLevel string = "info"
LogMaxDays int64 = 3
PrivilegeMode bool = false
PrivilegeToken string = ""
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
PrivilegeAllowPorts map[int64]struct{}
MaxPoolCount int64 = 100
HeartBeatTimeout int64 = 90
UserConnTimeout int64 = 10
2016-04-18 07:16:40 +00:00
2016-06-13 14:19:24 +00:00
VhostHttpMuxer *vhost.HttpMuxer
VhostHttpsMuxer *vhost.HttpsMuxer
ProxyServers map[string]*ProxyServer = make(map[string]*ProxyServer) // all proxy servers info and resources
ProxyServersMutex sync.RWMutex
2016-01-27 13:24:36 +00:00
)
func LoadConf(confFile string) (err error) {
err = loadCommonConf(confFile)
if err != nil {
return err
}
// load all proxy server's configure and initialize
// and set ProxyServers map
newProxyServers, err := loadProxyConf(confFile)
if err != nil {
return err
}
for _, proxyServer := range newProxyServers {
proxyServer.Init()
}
ProxyServersMutex.Lock()
ProxyServers = newProxyServers
ProxyServersMutex.Unlock()
return nil
}
func loadCommonConf(confFile string) error {
2016-01-27 13:24:36 +00:00
var tmpStr string
var ok bool
conf, err := ini.LoadFile(confFile)
if err != nil {
return err
}
// common
tmpStr, ok = conf.Get("common", "bind_addr")
if ok {
BindAddr = tmpStr
}
tmpStr, ok = conf.Get("common", "bind_port")
if ok {
v, err := strconv.ParseInt(tmpStr, 10, 64)
if err == nil {
BindPort = v
}
2016-01-27 13:24:36 +00:00
}
2016-04-18 07:16:40 +00:00
tmpStr, ok = conf.Get("common", "vhost_http_port")
if ok {
VhostHttpPort, _ = strconv.ParseInt(tmpStr, 10, 64)
} else {
VhostHttpPort = 0
}
2016-06-13 14:19:24 +00:00
tmpStr, ok = conf.Get("common", "vhost_https_port")
if ok {
VhostHttpsPort, _ = strconv.ParseInt(tmpStr, 10, 64)
} else {
VhostHttpsPort = 0
}
tmpStr, ok = conf.Get("common", "dashboard_port")
if ok {
DashboardPort, _ = strconv.ParseInt(tmpStr, 10, 64)
} else {
DashboardPort = 0
}
tmpStr, ok = conf.Get("common", "assets_dir")
if ok {
AssetsDir = tmpStr
}
2016-01-27 13:24:36 +00:00
tmpStr, ok = conf.Get("common", "log_file")
if ok {
LogFile = tmpStr
2016-03-13 16:21:40 +00:00
if LogFile == "console" {
LogWay = "console"
} else {
LogWay = "file"
}
2016-01-27 13:24:36 +00:00
}
tmpStr, ok = conf.Get("common", "log_level")
if ok {
LogLevel = tmpStr
}
tmpStr, ok = conf.Get("common", "log_max_days")
if ok {
v, err := strconv.ParseInt(tmpStr, 10, 64)
if err == nil {
LogMaxDays = v
}
}
2016-06-26 14:36:07 +00:00
tmpStr, ok = conf.Get("common", "privilege_mode")
if ok {
if tmpStr == "true" {
PrivilegeMode = true
}
}
if PrivilegeMode == true {
2016-06-27 16:21:13 +00:00
tmpStr, ok = conf.Get("common", "privilege_token")
2016-06-26 14:36:07 +00:00
if ok {
2016-06-27 16:21:13 +00:00
if tmpStr == "" {
return fmt.Errorf("Parse conf error: privilege_token can not be null")
}
PrivilegeToken = tmpStr
2016-06-26 14:36:07 +00:00
} else {
2016-06-27 16:21:13 +00:00
return fmt.Errorf("Parse conf error: privilege_token must be set if privilege_mode is enabled")
2016-06-26 14:36:07 +00:00
}
PrivilegeAllowPorts = make(map[int64]struct{})
tmpStr, ok = conf.Get("common", "privilege_allow_ports")
if ok {
// for example: 1000-2000,2001,2002,3000-4000
portRanges := strings.Split(tmpStr, ",")
for _, portRangeStr := range portRanges {
// 1000-2000 or 2001
portArray := strings.Split(portRangeStr, "-")
// lenght: only 1 or 2 is correct
rangeType := len(portArray)
if rangeType == 1 {
singlePort, err := strconv.ParseInt(portArray[0], 10, 64)
if err != nil {
return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err)
}
PrivilegeAllowPorts[singlePort] = struct{}{}
} else if rangeType == 2 {
min, err := strconv.ParseInt(portArray[0], 10, 64)
if err != nil {
return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err)
}
max, err := strconv.ParseInt(portArray[1], 10, 64)
if err != nil {
return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect, %v", err)
}
if max < min {
return fmt.Errorf("Parse conf error: privilege_allow_ports range incorrect")
}
for i := min; i <= max; i++ {
PrivilegeAllowPorts[i] = struct{}{}
}
} else {
return fmt.Errorf("Parse conf error: privilege_allow_ports is incorrect")
}
}
}
2016-06-26 14:36:07 +00:00
}
2016-07-29 15:08:00 +00:00
tmpStr, ok = conf.Get("common", "max_pool_count")
if ok {
v, err := strconv.ParseInt(tmpStr, 10, 64)
if err == nil && v >= 0 {
MaxPoolCount = v
}
}
return nil
}
func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err error) {
var ok bool
proxyServers = make(map[string]*ProxyServer)
conf, err := ini.LoadFile(confFile)
if err != nil {
return proxyServers, err
}
2016-01-27 13:24:36 +00:00
// servers
for name, section := range conf {
if name != "common" {
proxyServer := NewProxyServer()
2016-01-27 13:24:36 +00:00
proxyServer.Name = name
2016-04-18 07:16:40 +00:00
proxyServer.Type, ok = section["type"]
if ok {
2016-06-13 14:19:24 +00:00
if proxyServer.Type != "tcp" && proxyServer.Type != "http" && proxyServer.Type != "https" {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] type error", proxyServer.Name)
2016-04-18 07:16:40 +00:00
}
} else {
proxyServer.Type = "tcp"
}
proxyServer.AuthToken, ok = section["auth_token"]
2016-01-27 13:24:36 +00:00
if !ok {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] no auth_token found", proxyServer.Name)
2016-01-27 13:24:36 +00:00
}
2016-04-18 07:16:40 +00:00
// for tcp
if proxyServer.Type == "tcp" {
proxyServer.BindAddr, ok = section["bind_addr"]
if !ok {
proxyServer.BindAddr = "0.0.0.0"
}
2016-01-27 13:24:36 +00:00
2016-04-18 07:16:40 +00:00
portStr, ok := section["listen_port"]
if ok {
proxyServer.ListenPort, err = strconv.ParseInt(portStr, 10, 64)
if err != nil {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] listen_port error", proxyServer.Name)
2016-04-18 07:16:40 +00:00
}
} else {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] listen_port not found", proxyServer.Name)
2016-04-18 07:16:40 +00:00
}
} else if proxyServer.Type == "http" {
// for http
proxyServer.ListenPort = VhostHttpPort
2016-04-18 07:16:40 +00:00
domainStr, ok := section["custom_domains"]
if ok {
proxyServer.CustomDomains = strings.Split(domainStr, ",")
if len(proxyServer.CustomDomains) == 0 {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type equals http", proxyServer.Name)
}
2016-04-18 07:16:40 +00:00
for i, domain := range proxyServer.CustomDomains {
2016-06-24 07:43:58 +00:00
proxyServer.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
2016-04-18 07:16:40 +00:00
}
2016-06-26 14:36:07 +00:00
} else {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type equals http", proxyServer.Name)
2016-06-13 14:19:24 +00:00
}
} else if proxyServer.Type == "https" {
// for https
proxyServer.ListenPort = VhostHttpsPort
2016-06-13 14:19:24 +00:00
domainStr, ok := section["custom_domains"]
if ok {
proxyServer.CustomDomains = strings.Split(domainStr, ",")
if len(proxyServer.CustomDomains) == 0 {
2016-06-24 07:43:58 +00:00
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type equals https", proxyServer.Name)
2016-06-13 14:19:24 +00:00
}
for i, domain := range proxyServer.CustomDomains {
2016-06-24 07:43:58 +00:00
proxyServer.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
2016-06-13 14:19:24 +00:00
}
2016-06-26 14:36:07 +00:00
} else {
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type equals https", proxyServer.Name)
2016-01-27 13:24:36 +00:00
}
}
proxyServers[proxyServer.Name] = proxyServer
}
}
// set metric statistics of all proxies
for name, p := range proxyServers {
metric.SetProxyInfo(name, p.Type, p.BindAddr, p.UseEncryption, p.UseGzip,
p.PrivilegeMode, p.CustomDomains, p.ListenPort)
}
return proxyServers, nil
}
2016-01-27 13:24:36 +00:00
// the function can only reload proxy configures
// common section won't be changed
func ReloadConf(confFile string) (err error) {
loadProxyServers, err := loadProxyConf(confFile)
if err != nil {
return err
}
ProxyServersMutex.Lock()
for name, proxyServer := range loadProxyServers {
oldProxyServer, ok := ProxyServers[name]
if ok {
if !oldProxyServer.Compare(proxyServer) {
oldProxyServer.Close()
proxyServer.Init()
ProxyServers[name] = proxyServer
log.Info("ProxyName [%s] configure change, restart", name)
}
} else {
2016-01-27 13:24:36 +00:00
proxyServer.Init()
ProxyServers[name] = proxyServer
log.Info("ProxyName [%s] is new, init it", name)
2016-01-27 13:24:36 +00:00
}
}
2016-06-26 14:36:07 +00:00
// proxies created by PrivilegeMode won't be deleted
for name, oldProxyServer := range ProxyServers {
_, ok := loadProxyServers[name]
if !ok {
2016-06-26 14:36:07 +00:00
if !oldProxyServer.PrivilegeMode {
oldProxyServer.Close()
delete(ProxyServers, name)
log.Info("ProxyName [%s] deleted, close it", name)
} else {
log.Info("ProxyName [%s] created by PrivilegeMode, won't be closed", name)
}
}
2016-01-27 13:24:36 +00:00
}
ProxyServersMutex.Unlock()
2016-01-27 13:24:36 +00:00
return nil
}
2016-06-26 14:36:07 +00:00
func CreateProxy(s *ProxyServer) error {
ProxyServersMutex.Lock()
defer ProxyServersMutex.Unlock()
oldServer, ok := ProxyServers[s.Name]
if ok {
if oldServer.Status == consts.Working {
return fmt.Errorf("this proxy is already working now")
}
oldServer.Close()
if oldServer.PrivilegeMode {
delete(ProxyServers, s.Name)
}
}
ProxyServers[s.Name] = s
metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip,
s.PrivilegeMode, s.CustomDomains, s.ListenPort)
s.Init()
2016-06-26 14:36:07 +00:00
return nil
}
func DeleteProxy(proxyName string) {
ProxyServersMutex.Lock()
defer ProxyServersMutex.Unlock()
delete(ProxyServers, proxyName)
}