mirror of
https://github.com/fatedier/frp.git
synced 2025-10-30 14:17:31 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f9749488a | ||
|
|
f9a0d891a1 | ||
|
|
92daa45b68 | ||
|
|
5f20a22b0d | ||
|
|
63be94c611 | ||
|
|
694ee44af6 | ||
|
|
edb97abf50 | ||
|
|
0c10279deb | ||
|
|
1f49510e3e | ||
|
|
1868b3bafb | ||
|
|
a23521885c | ||
|
|
c80dcd050d | ||
|
|
043ab62587 | ||
|
|
a8969b1901 | ||
|
|
e26285eefc | ||
|
|
299bd7b5cb | ||
|
|
90d1384bf7 | ||
|
|
a5434e31b7 |
@@ -3,15 +3,23 @@ export GO15VENDOREXPERIMENT := 1
|
||||
|
||||
all: build
|
||||
|
||||
build: gox app more
|
||||
|
||||
gox:
|
||||
go get github.com/mitchellh/gox
|
||||
build: app
|
||||
|
||||
app:
|
||||
gox -osarch "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm windows/386 windows/amd64" ./src/...
|
||||
|
||||
more:
|
||||
env GOOS=darwin GOARCH=386 go build -o ./frpc_darwin_386 ./src/cmd/frpc
|
||||
env GOOS=darwin GOARCH=386 go build -o ./frps_darwin_386 ./src/cmd/frps
|
||||
env GOOS=darwin GOARCH=amd64 go build -o ./frpc_darwin_amd64 ./src/cmd/frpc
|
||||
env GOOS=darwin GOARCH=amd64 go build -o ./frps_darwin_amd64 ./src/cmd/frps
|
||||
env GOOS=linux GOARCH=386 go build -o ./frpc_linux_386 ./src/cmd/frpc
|
||||
env GOOS=linux GOARCH=386 go build -o ./frps_linux_386 ./src/cmd/frps
|
||||
env GOOS=linux GOARCH=amd64 go build -o ./frpc_linux_amd64 ./src/cmd/frpc
|
||||
env GOOS=linux GOARCH=amd64 go build -o ./frps_linux_amd64 ./src/cmd/frps
|
||||
env GOOS=linux GOARCH=arm go build -o ./frpc_linux_arm ./src/cmd/frpc
|
||||
env GOOS=linux GOARCH=arm go build -o ./frps_linux_arm ./src/cmd/frps
|
||||
env GOOS=windows GOARCH=386 go build -o ./frpc_windows_386.exe ./src/cmd/frpc
|
||||
env GOOS=windows GOARCH=386 go build -o ./frps_windows_386.exe ./src/cmd/frps
|
||||
env GOOS=windows GOARCH=amd64 go build -o ./frpc_windows_amd64.exe ./src/cmd/frpc
|
||||
env GOOS=windows GOARCH=amd64 go build -o ./frps_windows_amd64.exe ./src/cmd/frps
|
||||
env GOOS=linux GOARCH=mips64 go build -o ./frpc_linux_mips64 ./src/cmd/frpc
|
||||
env GOOS=linux GOARCH=mips64 go build -o ./frps_linux_mips64 ./src/cmd/frps
|
||||
env GOOS=linux GOARCH=mips64le go build -o ./frpc_linux_mips64le ./src/cmd/frpc
|
||||
|
||||
@@ -219,7 +219,7 @@ Then visit `http://[server_addr]:7500` to see dashboard, default username and pa
|
||||
|
||||
Client that want's to register must set a global `auth_token` equals to frps.ini.
|
||||
|
||||
Note that time duration bewtween frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
||||
Note that time duration between frpc and frps mustn't exceed 15 minutes because timestamp is used for authentication.
|
||||
|
||||
Howerver, this timeout duration can be modified by setting `authentication_timeout` in frps's configure file. It's defalut value is 900, means 15 minutes. If it is equals 0, then frps will not check authentication timeout.
|
||||
|
||||
@@ -452,7 +452,6 @@ http_proxy = http://user:pwd@192.168.1.128:8080
|
||||
|
||||
## Development Plan
|
||||
|
||||
* Url router.
|
||||
* Log http request information in frps.
|
||||
* Direct reverse proxy, like haproxy.
|
||||
* Load balance to different service in frpc.
|
||||
@@ -497,3 +496,5 @@ Donate money by [paypal](https://www.paypal.me/fatedier) to my account **fatedie
|
||||
* [Damon Zhao](https://github.com/se77en)
|
||||
* [Manfred Touron](https://github.com/moul)
|
||||
* [xuebing1110](https://github.com/xuebing1110)
|
||||
* [Anbitioner](https://github.com/bingtianbaihua)
|
||||
* [LitleCarl](https://github.com/LitleCarl)
|
||||
|
||||
@@ -469,7 +469,6 @@ http_proxy = http://user:pwd@192.168.1.128:8080
|
||||
|
||||
计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 [issues](https://github.com/fatedier/frp/issues) 中反馈。
|
||||
|
||||
* 支持 url 路由转发。
|
||||
* frps 记录 http 请求日志。
|
||||
* frps 支持直接反向代理,类似 haproxy。
|
||||
* frpc 支持负载均衡到后端不同服务。
|
||||
@@ -516,3 +515,5 @@ frp 交流群:606194980 (QQ 群号)
|
||||
* [Damon Zhao](https://github.com/se77en)
|
||||
* [Manfred Touron](https://github.com/moul)
|
||||
* [xuebing1110](https://github.com/xuebing1110)
|
||||
* [Anbitioner](https://github.com/bingtianbaihua)
|
||||
* [LitleCarl](https://github.com/LitleCarl)
|
||||
|
||||
@@ -22,6 +22,10 @@ auth_token = 123
|
||||
# for privilege mode
|
||||
privilege_token = 12345678
|
||||
|
||||
# heartbeat configure, it's not recommended to modify the default value
|
||||
# the default value of heartbeat_interval is 10 and heartbeat_timeout is 30
|
||||
# heartbeat_interval = 10
|
||||
# heartbeat_timeout = 30
|
||||
|
||||
# ssh is the proxy name same as server's configuration
|
||||
[ssh]
|
||||
|
||||
@@ -30,6 +30,10 @@ log_max_days = 3
|
||||
privilege_mode = true
|
||||
privilege_token = 12345678
|
||||
|
||||
# heartbeat configure, it's not recommended to modify the default value
|
||||
# the default value of heartbeat_timeout is 30
|
||||
# heartbeat_timeout = 30
|
||||
|
||||
# only allow frpc to bind ports you list, if you set nothing, there won't be any limit
|
||||
privilege_allow_ports = 2000-3000,3001,3003,4000-50000
|
||||
|
||||
|
||||
@@ -55,15 +55,24 @@ func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
|
||||
var heartbeatTimeout bool = false
|
||||
timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() {
|
||||
heartbeatTimeout = true
|
||||
c.Close()
|
||||
if c != nil {
|
||||
c.Close()
|
||||
}
|
||||
if cli != nil {
|
||||
// if it's not udp type, nothing will happen
|
||||
cli.CloseUdpTunnel()
|
||||
cli.SetCloseFlag(true)
|
||||
}
|
||||
log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name)
|
||||
})
|
||||
defer timer.Stop()
|
||||
|
||||
for {
|
||||
buf, err := c.ReadLine()
|
||||
if err == io.EOF || c == nil || c.IsClosed() {
|
||||
if err == io.EOF || c.IsClosed() {
|
||||
timer.Stop()
|
||||
c.Close()
|
||||
cli.SetCloseFlag(true)
|
||||
log.Warn("ProxyName [%s], frps close this control conn!", cli.Name)
|
||||
var delayTime time.Duration = 1
|
||||
|
||||
@@ -76,11 +85,14 @@ func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
|
||||
msgSendChan = make(chan interface{}, 1024)
|
||||
go heartbeatSender(c, msgSendChan)
|
||||
go msgSender(cli, c, msgSendChan)
|
||||
cli.SetCloseFlag(false)
|
||||
break
|
||||
}
|
||||
|
||||
if delayTime < 60 {
|
||||
if delayTime < 30 {
|
||||
delayTime = delayTime * 2
|
||||
} else {
|
||||
delayTime = 30
|
||||
}
|
||||
time.Sleep(delayTime * time.Second)
|
||||
}
|
||||
|
||||
@@ -85,7 +85,9 @@ func controlWorker(c *conn.Conn) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
closeFlag = false
|
||||
if ret == 0 {
|
||||
closeFlag = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -266,6 +268,20 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string, s *serv
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if s.SubDomain != "" {
|
||||
if strings.Contains(s.SubDomain, ".") || strings.Contains(s.SubDomain, "*") {
|
||||
info = fmt.Sprintf("ProxyName [%s], '.' and '*' is not supported in subdomain", req.ProxyName)
|
||||
log.Warn(info)
|
||||
return
|
||||
}
|
||||
if server.SubDomainHost == "" {
|
||||
info = fmt.Sprintf("ProxyName [%s], subdomain is not supported because this feature is not enabled by remote server", req.ProxyName)
|
||||
log.Warn(info)
|
||||
return
|
||||
}
|
||||
s.SubDomain = s.SubDomain + "." + server.SubDomainHost
|
||||
}
|
||||
}
|
||||
err := server.CreateProxy(s)
|
||||
if err != nil {
|
||||
@@ -295,20 +311,6 @@ func doLogin(req *msg.ControlReq, c *conn.Conn) (ret int64, info string, s *serv
|
||||
s.HttpUserName = req.HttpUserName
|
||||
s.HttpPassWord = req.HttpPassWord
|
||||
|
||||
// package URL
|
||||
if req.SubDomain != "" {
|
||||
if strings.Contains(req.SubDomain, ".") || strings.Contains(req.SubDomain, "*") {
|
||||
info = fmt.Sprintf("ProxyName [%s], '.' or '*' is not supported in subdomain", req.ProxyName)
|
||||
log.Warn(info)
|
||||
return
|
||||
}
|
||||
if server.SubDomainHost == "" {
|
||||
info = fmt.Sprintf("ProxyName [%s], subdomain in not supported because this feature is not enabled by remote server", req.ProxyName)
|
||||
log.Warn(info)
|
||||
return
|
||||
}
|
||||
s.SubDomain = req.SubDomain + "." + server.SubDomainHost
|
||||
}
|
||||
if req.PoolCount > server.MaxPoolCount {
|
||||
s.PoolCount = server.MaxPoolCount
|
||||
} else if req.PoolCount < 0 {
|
||||
|
||||
@@ -39,6 +39,9 @@ type ProxyClient struct {
|
||||
|
||||
udpTunnel *conn.Conn
|
||||
once sync.Once
|
||||
closeFlag bool
|
||||
|
||||
mutex sync.RWMutex
|
||||
}
|
||||
|
||||
// if proxy type is udp, keep a tcp connection for transferring udp packages
|
||||
@@ -48,7 +51,7 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
||||
var c *conn.Conn
|
||||
udpProcessor := NewUdpProcesser(nil, pc.LocalIp, pc.LocalPort)
|
||||
for {
|
||||
if pc.udpTunnel == nil || pc.udpTunnel.IsClosed() {
|
||||
if !pc.IsClosed() && (pc.udpTunnel == nil || pc.udpTunnel.IsClosed()) {
|
||||
if HttpProxy == "" {
|
||||
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port))
|
||||
} else {
|
||||
@@ -59,7 +62,7 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
||||
time.Sleep(10 * time.Second)
|
||||
continue
|
||||
}
|
||||
log.Info("ProxyName [%s], udp tunnel reconnect to server [%s:%d] success", pc.Name, addr, port)
|
||||
log.Info("ProxyName [%s], udp tunnel connect to server [%s:%d] success", pc.Name, addr, port)
|
||||
|
||||
nowTime := time.Now().Unix()
|
||||
req := &msg.ControlReq{
|
||||
@@ -82,8 +85,11 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
}
|
||||
pc.mutex.Lock()
|
||||
pc.udpTunnel = c
|
||||
udpProcessor.UpdateTcpConn(pc.udpTunnel)
|
||||
pc.mutex.Unlock()
|
||||
|
||||
udpProcessor.Run()
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
@@ -91,6 +97,14 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
|
||||
})
|
||||
}
|
||||
|
||||
func (pc *ProxyClient) CloseUdpTunnel() {
|
||||
pc.mutex.RLock()
|
||||
defer pc.mutex.RUnlock()
|
||||
if pc.udpTunnel != nil {
|
||||
pc.udpTunnel.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (pc *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
|
||||
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", pc.LocalIp, pc.LocalPort))
|
||||
if err != nil {
|
||||
@@ -158,3 +172,15 @@ func (pc *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *ProxyClient) SetCloseFlag(closeFlag bool) {
|
||||
pc.mutex.Lock()
|
||||
defer pc.mutex.Unlock()
|
||||
pc.closeFlag = closeFlag
|
||||
}
|
||||
|
||||
func (pc *ProxyClient) IsClosed() bool {
|
||||
pc.mutex.RLock()
|
||||
defer pc.mutex.RUnlock()
|
||||
return pc.closeFlag
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ var (
|
||||
LogLevel string = "info"
|
||||
LogMaxDays int64 = 3
|
||||
PrivilegeToken string = ""
|
||||
HeartBeatInterval int64 = 20
|
||||
HeartBeatTimeout int64 = 90
|
||||
HeartBeatInterval int64 = 10
|
||||
HeartBeatTimeout int64 = 30
|
||||
)
|
||||
|
||||
var ProxyClients map[string]*ProxyClient = make(map[string]*ProxyClient)
|
||||
@@ -98,6 +98,34 @@ func LoadConf(confFile string) (err error) {
|
||||
authToken = tmpStr
|
||||
}
|
||||
|
||||
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
||||
if ok {
|
||||
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||
} else {
|
||||
HeartBeatTimeout = v
|
||||
}
|
||||
}
|
||||
|
||||
tmpStr, ok = conf.Get("common", "heartbeat_interval")
|
||||
if ok {
|
||||
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse conf error: heartbeat_interval is incorrect")
|
||||
} else {
|
||||
HeartBeatInterval = v
|
||||
}
|
||||
}
|
||||
|
||||
if HeartBeatInterval <= 0 {
|
||||
return fmt.Errorf("Parse conf error: heartbeat_interval is incorrect")
|
||||
}
|
||||
|
||||
if HeartBeatTimeout < HeartBeatInterval {
|
||||
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect, heartbeat_timeout is less than heartbeat_interval")
|
||||
}
|
||||
|
||||
// proxies
|
||||
for name, section := range conf {
|
||||
if name != "common" {
|
||||
@@ -215,44 +243,48 @@ func LoadConf(confFile string) (err error) {
|
||||
}
|
||||
} else if proxyClient.Type == "http" {
|
||||
// custom_domains
|
||||
domainStr, ok := section["custom_domains"]
|
||||
tmpStr, ok = section["custom_domains"]
|
||||
if ok {
|
||||
proxyClient.CustomDomains = strings.Split(domainStr, ",")
|
||||
if len(proxyClient.CustomDomains) == 0 {
|
||||
ok = false
|
||||
} else {
|
||||
for i, domain := range proxyClient.CustomDomains {
|
||||
proxyClient.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
||||
}
|
||||
proxyClient.CustomDomains = strings.Split(tmpStr, ",")
|
||||
for i, domain := range proxyClient.CustomDomains {
|
||||
proxyClient.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
||||
}
|
||||
}
|
||||
|
||||
if !ok && proxyClient.SubDomain == "" {
|
||||
// subdomain
|
||||
tmpStr, ok = section["subdomain"]
|
||||
if ok {
|
||||
proxyClient.SubDomain = tmpStr
|
||||
}
|
||||
|
||||
if len(proxyClient.CustomDomains) == 0 && proxyClient.SubDomain == "" {
|
||||
return fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them when type is http", proxyClient.Name)
|
||||
}
|
||||
|
||||
// locations
|
||||
locations, ok := section["locations"]
|
||||
tmpStr, ok = section["locations"]
|
||||
if ok {
|
||||
proxyClient.Locations = strings.Split(locations, ",")
|
||||
proxyClient.Locations = strings.Split(tmpStr, ",")
|
||||
} else {
|
||||
proxyClient.Locations = []string{""}
|
||||
}
|
||||
} else if proxyClient.Type == "https" {
|
||||
// custom_domains
|
||||
domainStr, ok := section["custom_domains"]
|
||||
tmpStr, ok = section["custom_domains"]
|
||||
if ok {
|
||||
proxyClient.CustomDomains = strings.Split(domainStr, ",")
|
||||
if len(proxyClient.CustomDomains) == 0 {
|
||||
ok = false
|
||||
} else {
|
||||
for i, domain := range proxyClient.CustomDomains {
|
||||
proxyClient.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
||||
}
|
||||
proxyClient.CustomDomains = strings.Split(tmpStr, ",")
|
||||
for i, domain := range proxyClient.CustomDomains {
|
||||
proxyClient.CustomDomains[i] = strings.ToLower(strings.TrimSpace(domain))
|
||||
}
|
||||
}
|
||||
|
||||
if !ok && proxyClient.SubDomain == "" {
|
||||
// subdomain
|
||||
tmpStr, ok = section["subdomain"]
|
||||
if ok {
|
||||
proxyClient.SubDomain = tmpStr
|
||||
}
|
||||
|
||||
if len(proxyClient.CustomDomains) == 0 && proxyClient.SubDomain == "" {
|
||||
return fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them when type is https", proxyClient.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ var (
|
||||
// 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
|
||||
HeartBeatTimeout int64 = 30
|
||||
UserConnTimeout int64 = 10
|
||||
|
||||
VhostHttpMuxer *vhost.HttpMuxer
|
||||
@@ -237,6 +237,16 @@ func loadCommonConf(confFile string) error {
|
||||
if ok {
|
||||
SubDomainHost = strings.ToLower(strings.TrimSpace(SubDomainHost))
|
||||
}
|
||||
|
||||
tmpStr, ok = conf.Get("common", "heartbeat_timeout")
|
||||
if ok {
|
||||
v, err := strconv.ParseInt(tmpStr, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Parse conf error: heartbeat_timeout is incorrect")
|
||||
} else {
|
||||
HeartBeatTimeout = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -290,9 +300,6 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
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 is http", proxyServer.Name)
|
||||
}
|
||||
for i, domain := range proxyServer.CustomDomains {
|
||||
domain = strings.ToLower(strings.TrimSpace(domain))
|
||||
// custom domain should not belong to subdomain_host
|
||||
@@ -301,8 +308,23 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
}
|
||||
proxyServer.CustomDomains[i] = domain
|
||||
}
|
||||
} else {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type is http", proxyServer.Name)
|
||||
}
|
||||
|
||||
// subdomain
|
||||
subdomainStr, ok := section["subdomain"]
|
||||
if ok {
|
||||
if strings.Contains(subdomainStr, ".") || strings.Contains(subdomainStr, "*") {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] '.' and '*' is not supported in subdomain", proxyServer.Name)
|
||||
}
|
||||
|
||||
if SubDomainHost == "" {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] subdomain is not supported because subdomain_host is empty", proxyServer.Name)
|
||||
}
|
||||
proxyServer.SubDomain = subdomainStr + "." + SubDomainHost
|
||||
}
|
||||
|
||||
if len(proxyServer.CustomDomains) == 0 && proxyServer.SubDomain == "" {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them when type is http", proxyServer.Name)
|
||||
}
|
||||
|
||||
// locations
|
||||
@@ -319,9 +341,6 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
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 is https", proxyServer.Name)
|
||||
}
|
||||
for i, domain := range proxyServer.CustomDomains {
|
||||
domain = strings.ToLower(strings.TrimSpace(domain))
|
||||
if SubDomainHost != "" && strings.Contains(domain, SubDomainHost) {
|
||||
@@ -329,8 +348,23 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
}
|
||||
proxyServer.CustomDomains[i] = domain
|
||||
}
|
||||
} else {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains must be set when type is https", proxyServer.Name)
|
||||
}
|
||||
|
||||
// subdomain
|
||||
subdomainStr, ok := section["subdomain"]
|
||||
if ok {
|
||||
if strings.Contains(subdomainStr, ".") || strings.Contains(subdomainStr, "*") {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] '.' and '*' is not supported in subdomain", proxyServer.Name)
|
||||
}
|
||||
|
||||
if SubDomainHost == "" {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] subdomain is not supported because subdomain_host is empty", proxyServer.Name)
|
||||
}
|
||||
proxyServer.SubDomain = subdomainStr + "." + SubDomainHost
|
||||
}
|
||||
|
||||
if len(proxyServer.CustomDomains) == 0 && proxyServer.SubDomain == "" {
|
||||
return proxyServers, fmt.Errorf("Parse conf error: proxy [%s] custom_domains and subdomain should set at least one of them when type is https", proxyServer.Name)
|
||||
}
|
||||
}
|
||||
proxyServers[proxyServer.Name] = proxyServer
|
||||
@@ -395,7 +429,9 @@ func CreateProxy(s *ProxyServer) error {
|
||||
if oldServer.Status == consts.Working {
|
||||
return fmt.Errorf("this proxy is already working now")
|
||||
}
|
||||
oldServer.Lock()
|
||||
oldServer.Release()
|
||||
oldServer.Unlock()
|
||||
if oldServer.PrivilegeMode {
|
||||
delete(ProxyServers, s.Name)
|
||||
}
|
||||
@@ -403,7 +439,6 @@ func CreateProxy(s *ProxyServer) error {
|
||||
ProxyServers[s.Name] = s
|
||||
metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip,
|
||||
s.PrivilegeMode, s.CustomDomains, s.Locations, s.ListenPort)
|
||||
s.Init()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -79,10 +79,13 @@ func NewProxyServerFromCtlMsg(req *msg.ControlReq) (p *ProxyServer) {
|
||||
p.ListenPort = VhostHttpsPort
|
||||
}
|
||||
p.CustomDomains = req.CustomDomains
|
||||
p.SubDomain = req.SubDomain
|
||||
p.Locations = req.Locations
|
||||
p.HostHeaderRewrite = req.HostHeaderRewrite
|
||||
p.HttpUserName = req.HttpUserName
|
||||
p.HttpPassWord = req.HttpPassWord
|
||||
|
||||
p.Init()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -276,10 +279,14 @@ func (p *ProxyServer) Start(c *conn.Conn) (err error) {
|
||||
}
|
||||
|
||||
func (p *ProxyServer) Close() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
oldStatus := p.Status
|
||||
p.Release()
|
||||
|
||||
// if the proxy created by PrivilegeMode, delete it when closed
|
||||
if p.PrivilegeMode {
|
||||
if p.PrivilegeMode && oldStatus == consts.Working {
|
||||
// NOTE: this will take the global ProxyServerMap's lock
|
||||
// if we only want to release resources, use Release() instead
|
||||
DeleteProxy(p.Name)
|
||||
@@ -287,9 +294,6 @@ func (p *ProxyServer) Close() {
|
||||
}
|
||||
|
||||
func (p *ProxyServer) Release() {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
if p.Status != consts.Closed {
|
||||
p.Status = consts.Closed
|
||||
for _, l := range p.listeners {
|
||||
@@ -297,10 +301,22 @@ func (p *ProxyServer) Release() {
|
||||
l.Close()
|
||||
}
|
||||
}
|
||||
close(p.ctlMsgChan)
|
||||
close(p.workConnChan)
|
||||
close(p.udpSenderChan)
|
||||
close(p.closeChan)
|
||||
if p.ctlMsgChan != nil {
|
||||
close(p.ctlMsgChan)
|
||||
p.ctlMsgChan = nil
|
||||
}
|
||||
if p.workConnChan != nil {
|
||||
close(p.workConnChan)
|
||||
p.workConnChan = nil
|
||||
}
|
||||
if p.udpSenderChan != nil {
|
||||
close(p.udpSenderChan)
|
||||
p.udpSenderChan = nil
|
||||
}
|
||||
if p.closeChan != nil {
|
||||
close(p.closeChan)
|
||||
p.closeChan = nil
|
||||
}
|
||||
if p.CtlConn != nil {
|
||||
p.CtlConn.Close()
|
||||
}
|
||||
@@ -429,6 +445,12 @@ func (p *ProxyServer) getWorkConn() (workConn *conn.Conn, err error) {
|
||||
}
|
||||
|
||||
func (p *ProxyServer) connectionPoolManager(closeCh <-chan struct{}) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Warn("ProxyName [%s], connectionPoolManager panic %v", p.Name, r)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
// check if we need more work connections and send messages to frpc to get more
|
||||
time.Sleep(time.Duration(2) * time.Second)
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var version string = "0.9.1"
|
||||
var version string = "0.9.3"
|
||||
|
||||
func Full() string {
|
||||
return version
|
||||
|
||||
Reference in New Issue
Block a user