Merge pull request #217 from fatedier/dev

bump version to 0.9.2
This commit is contained in:
fatedier 2017-01-08 09:22:28 -06:00 committed by GitHub
commit edb97abf50
12 changed files with 139 additions and 29 deletions

View File

@ -3,15 +3,23 @@ export GO15VENDOREXPERIMENT := 1
all: build all: build
build: gox app more build: app
gox:
go get github.com/mitchellh/gox
app: app:
gox -osarch "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm windows/386 windows/amd64" ./src/... 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
more: 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 ./frpc_linux_mips64 ./src/cmd/frpc
env GOOS=linux GOARCH=mips64 go build -o ./frps_linux_mips64 ./src/cmd/frps 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 env GOOS=linux GOARCH=mips64le go build -o ./frpc_linux_mips64le ./src/cmd/frpc

View File

@ -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. 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. 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 ## Development Plan
* Url router.
* Log http request information in frps. * Log http request information in frps.
* Direct reverse proxy, like haproxy. * Direct reverse proxy, like haproxy.
* Load balance to different service in frpc. * Load balance to different service in frpc.
@ -497,3 +496,4 @@ Donate money by [paypal](https://www.paypal.me/fatedier) to my account **fatedie
* [Damon Zhao](https://github.com/se77en) * [Damon Zhao](https://github.com/se77en)
* [Manfred Touron](https://github.com/moul) * [Manfred Touron](https://github.com/moul)
* [xuebing1110](https://github.com/xuebing1110) * [xuebing1110](https://github.com/xuebing1110)
* [Anbitioner](https://github.com/bingtianbaihua)

View File

@ -469,7 +469,6 @@ http_proxy = http://user:pwd@192.168.1.128:8080
计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 [issues](https://github.com/fatedier/frp/issues) 中反馈。 计划在后续版本中加入的功能与优化,排名不分先后,如果有其他功能建议欢迎在 [issues](https://github.com/fatedier/frp/issues) 中反馈。
* 支持 url 路由转发。
* frps 记录 http 请求日志。 * frps 记录 http 请求日志。
* frps 支持直接反向代理,类似 haproxy。 * frps 支持直接反向代理,类似 haproxy。
* frpc 支持负载均衡到后端不同服务。 * frpc 支持负载均衡到后端不同服务。
@ -516,3 +515,4 @@ frp 交流群606194980 (QQ 群号)
* [Damon Zhao](https://github.com/se77en) * [Damon Zhao](https://github.com/se77en)
* [Manfred Touron](https://github.com/moul) * [Manfred Touron](https://github.com/moul)
* [xuebing1110](https://github.com/xuebing1110) * [xuebing1110](https://github.com/xuebing1110)
* [Anbitioner](https://github.com/bingtianbaihua)

View File

@ -22,6 +22,10 @@ auth_token = 123
# for privilege mode # for privilege mode
privilege_token = 12345678 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 is the proxy name same as server's configuration
[ssh] [ssh]

View File

@ -30,6 +30,10 @@ log_max_days = 3
privilege_mode = true privilege_mode = true
privilege_token = 12345678 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 # 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 privilege_allow_ports = 2000-3000,3001,3003,4000-50000

View File

@ -55,15 +55,24 @@ func msgReader(cli *client.ProxyClient, c *conn.Conn, msgSendChan chan interface
var heartbeatTimeout bool = false var heartbeatTimeout bool = false
timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() { timer := time.AfterFunc(time.Duration(client.HeartBeatTimeout)*time.Second, func() {
heartbeatTimeout = true 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) log.Error("ProxyName [%s], heartbeatRes from frps timeout", cli.Name)
}) })
defer timer.Stop() defer timer.Stop()
for { for {
buf, err := c.ReadLine() buf, err := c.ReadLine()
if err == io.EOF || c == nil || c.IsClosed() { if err == io.EOF || c.IsClosed() {
timer.Stop()
c.Close() c.Close()
cli.SetCloseFlag(true)
log.Warn("ProxyName [%s], frps close this control conn!", cli.Name) log.Warn("ProxyName [%s], frps close this control conn!", cli.Name)
var delayTime time.Duration = 1 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) msgSendChan = make(chan interface{}, 1024)
go heartbeatSender(c, msgSendChan) go heartbeatSender(c, msgSendChan)
go msgSender(cli, c, msgSendChan) go msgSender(cli, c, msgSendChan)
cli.SetCloseFlag(false)
break break
} }
if delayTime < 60 { if delayTime < 30 {
delayTime = delayTime * 2 delayTime = delayTime * 2
} else {
delayTime = 30
} }
time.Sleep(delayTime * time.Second) time.Sleep(delayTime * time.Second)
} }

View File

@ -85,7 +85,9 @@ func controlWorker(c *conn.Conn) {
return return
} }
} else { } else {
closeFlag = false if ret == 0 {
closeFlag = false
}
return return
} }

View File

@ -39,6 +39,9 @@ type ProxyClient struct {
udpTunnel *conn.Conn udpTunnel *conn.Conn
once sync.Once once sync.Once
closeFlag bool
mutex sync.RWMutex
} }
// if proxy type is udp, keep a tcp connection for transferring udp packages // 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 var c *conn.Conn
udpProcessor := NewUdpProcesser(nil, pc.LocalIp, pc.LocalPort) udpProcessor := NewUdpProcesser(nil, pc.LocalIp, pc.LocalPort)
for { for {
if pc.udpTunnel == nil || pc.udpTunnel.IsClosed() { if !pc.IsClosed() && (pc.udpTunnel == nil || pc.udpTunnel.IsClosed()) {
if HttpProxy == "" { if HttpProxy == "" {
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port)) c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", addr, port))
} else { } else {
@ -59,7 +62,7 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
continue 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() nowTime := time.Now().Unix()
req := &msg.ControlReq{ req := &msg.ControlReq{
@ -82,8 +85,11 @@ func (pc *ProxyClient) StartUdpTunnelOnce(addr string, port int64) {
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
continue continue
} }
pc.mutex.Lock()
pc.udpTunnel = c pc.udpTunnel = c
udpProcessor.UpdateTcpConn(pc.udpTunnel) udpProcessor.UpdateTcpConn(pc.udpTunnel)
pc.mutex.Unlock()
udpProcessor.Run() udpProcessor.Run()
} }
time.Sleep(1 * time.Second) 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) { func (pc *ProxyClient) GetLocalConn() (c *conn.Conn, err error) {
c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", pc.LocalIp, pc.LocalPort)) c, err = conn.ConnectServer(fmt.Sprintf("%s:%d", pc.LocalIp, pc.LocalPort))
if err != nil { if err != nil {
@ -158,3 +172,15 @@ func (pc *ProxyClient) StartTunnel(serverAddr string, serverPort int64) (err err
return nil 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
}

View File

@ -33,8 +33,8 @@ var (
LogLevel string = "info" LogLevel string = "info"
LogMaxDays int64 = 3 LogMaxDays int64 = 3
PrivilegeToken string = "" PrivilegeToken string = ""
HeartBeatInterval int64 = 20 HeartBeatInterval int64 = 10
HeartBeatTimeout int64 = 90 HeartBeatTimeout int64 = 30
) )
var ProxyClients map[string]*ProxyClient = make(map[string]*ProxyClient) var ProxyClients map[string]*ProxyClient = make(map[string]*ProxyClient)
@ -98,6 +98,34 @@ func LoadConf(confFile string) (err error) {
authToken = tmpStr 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 // proxies
for name, section := range conf { for name, section := range conf {
if name != "common" { if name != "common" {

View File

@ -51,7 +51,7 @@ var (
// if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected // if PrivilegeAllowPorts is not nil, tcp proxies which remote port exist in this map can be connected
PrivilegeAllowPorts map[int64]struct{} PrivilegeAllowPorts map[int64]struct{}
MaxPoolCount int64 = 100 MaxPoolCount int64 = 100
HeartBeatTimeout int64 = 90 HeartBeatTimeout int64 = 30
UserConnTimeout int64 = 10 UserConnTimeout int64 = 10
VhostHttpMuxer *vhost.HttpMuxer VhostHttpMuxer *vhost.HttpMuxer
@ -237,6 +237,16 @@ func loadCommonConf(confFile string) error {
if ok { if ok {
SubDomainHost = strings.ToLower(strings.TrimSpace(SubDomainHost)) 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 return nil
} }
@ -395,7 +405,9 @@ func CreateProxy(s *ProxyServer) error {
if oldServer.Status == consts.Working { if oldServer.Status == consts.Working {
return fmt.Errorf("this proxy is already working now") return fmt.Errorf("this proxy is already working now")
} }
oldServer.Lock()
oldServer.Release() oldServer.Release()
oldServer.Unlock()
if oldServer.PrivilegeMode { if oldServer.PrivilegeMode {
delete(ProxyServers, s.Name) delete(ProxyServers, s.Name)
} }
@ -403,7 +415,6 @@ func CreateProxy(s *ProxyServer) error {
ProxyServers[s.Name] = s ProxyServers[s.Name] = s
metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip, metric.SetProxyInfo(s.Name, s.Type, s.BindAddr, s.UseEncryption, s.UseGzip,
s.PrivilegeMode, s.CustomDomains, s.Locations, s.ListenPort) s.PrivilegeMode, s.CustomDomains, s.Locations, s.ListenPort)
s.Init()
return nil return nil
} }

View File

@ -83,6 +83,8 @@ func NewProxyServerFromCtlMsg(req *msg.ControlReq) (p *ProxyServer) {
p.HostHeaderRewrite = req.HostHeaderRewrite p.HostHeaderRewrite = req.HostHeaderRewrite
p.HttpUserName = req.HttpUserName p.HttpUserName = req.HttpUserName
p.HttpPassWord = req.HttpPassWord p.HttpPassWord = req.HttpPassWord
p.Init()
return return
} }
@ -276,10 +278,14 @@ func (p *ProxyServer) Start(c *conn.Conn) (err error) {
} }
func (p *ProxyServer) Close() { func (p *ProxyServer) Close() {
p.Lock()
defer p.Unlock()
oldStatus := p.Status
p.Release() p.Release()
// if the proxy created by PrivilegeMode, delete it when closed // if the proxy created by PrivilegeMode, delete it when closed
if p.PrivilegeMode { if p.PrivilegeMode && oldStatus != consts.Closed {
// NOTE: this will take the global ProxyServerMap's lock // NOTE: this will take the global ProxyServerMap's lock
// if we only want to release resources, use Release() instead // if we only want to release resources, use Release() instead
DeleteProxy(p.Name) DeleteProxy(p.Name)
@ -287,9 +293,6 @@ func (p *ProxyServer) Close() {
} }
func (p *ProxyServer) Release() { func (p *ProxyServer) Release() {
p.Lock()
defer p.Unlock()
if p.Status != consts.Closed { if p.Status != consts.Closed {
p.Status = consts.Closed p.Status = consts.Closed
for _, l := range p.listeners { for _, l := range p.listeners {
@ -297,10 +300,22 @@ func (p *ProxyServer) Release() {
l.Close() l.Close()
} }
} }
close(p.ctlMsgChan) if p.ctlMsgChan != nil {
close(p.workConnChan) close(p.ctlMsgChan)
close(p.udpSenderChan) p.ctlMsgChan = nil
close(p.closeChan) }
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 { if p.CtlConn != nil {
p.CtlConn.Close() p.CtlConn.Close()
} }

View File

@ -19,7 +19,7 @@ import (
"strings" "strings"
) )
var version string = "0.9.1" var version string = "0.9.2"
func Full() string { func Full() string {
return version return version