mirror of https://github.com/fatedier/frp
commit
e62d9a5242
|
@ -66,7 +66,7 @@ Now it also try to support p2p connect.
|
||||||
|
|
||||||
frp is under development and you can try it with latest release version. Master branch for releasing stable version when dev branch for developing.
|
frp is under development and you can try it with latest release version. Master branch for releasing stable version when dev branch for developing.
|
||||||
|
|
||||||
**We may change any protocol and can't promise backward compatible. Please check the release log when upgrading.**
|
**We may change any protocol and can't promise backward compatibility. Please check the release log when upgrading.**
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
|
@ -265,6 +265,7 @@ Configure frps same as above.
|
||||||
plugin_crt_path = ./server.crt
|
plugin_crt_path = ./server.crt
|
||||||
plugin_key_path = ./server.key
|
plugin_key_path = ./server.key
|
||||||
plugin_host_header_rewrite = 127.0.0.1
|
plugin_host_header_rewrite = 127.0.0.1
|
||||||
|
plugin_header_X-From-Where = frp
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Visit `https://test.yourdomain.com`.
|
2. Visit `https://test.yourdomain.com`.
|
||||||
|
|
|
@ -129,7 +129,7 @@ master 分支用于发布稳定版本,dev 分支用于开发,您可以尝试
|
||||||
vhost_http_port = 8080
|
vhost_http_port = 8080
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 启动 frps;
|
2. 启动 frps:
|
||||||
|
|
||||||
`./frps -c ./frps.ini`
|
`./frps -c ./frps.ini`
|
||||||
|
|
||||||
|
@ -270,6 +270,7 @@ frps 的部署步骤同上。
|
||||||
plugin_crt_path = ./server.crt
|
plugin_crt_path = ./server.crt
|
||||||
plugin_key_path = ./server.key
|
plugin_key_path = ./server.key
|
||||||
plugin_host_header_rewrite = 127.0.0.1
|
plugin_host_header_rewrite = 127.0.0.1
|
||||||
|
plugin_header_X-From-Where = frp
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 通过浏览器访问 `https://test.yourdomain.com` 即可。
|
2. 通过浏览器访问 `https://test.yourdomain.com` 即可。
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -36,7 +35,7 @@ func (svr *Service) RunAdminServer(addr string, port int) (err error) {
|
||||||
// url router
|
// url router
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
user, passwd := g.GlbClientCfg.AdminUser, g.GlbClientCfg.AdminPwd
|
user, passwd := svr.cfg.AdminUser, svr.cfg.AdminPwd
|
||||||
router.Use(frpNet.NewHttpAuthMiddleware(user, passwd).Middleware)
|
router.Use(frpNet.NewHttpAuthMiddleware(user, passwd).Middleware)
|
||||||
|
|
||||||
// api, see dashboard_api.go
|
// api, see dashboard_api.go
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client/proxy"
|
"github.com/fatedier/frp/client/proxy"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
)
|
)
|
||||||
|
@ -47,7 +46,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
content, err := config.GetRenderedConfFromFile(g.GlbClientCfg.CfgFile)
|
content, err := config.GetRenderedConfFromFile(svr.cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
|
@ -55,7 +54,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newCommonCfg, err := config.UnmarshalClientConfFromIni(nil, content)
|
newCommonCfg, err := config.UnmarshalClientConfFromIni(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
|
@ -63,7 +62,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, content, newCommonCfg.Start)
|
pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(svr.cfg.User, content, newCommonCfg.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
|
@ -107,7 +106,7 @@ func (a ByProxyStatusResp) Len() int { return len(a) }
|
||||||
func (a ByProxyStatusResp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a ByProxyStatusResp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a ByProxyStatusResp) Less(i, j int) bool { return strings.Compare(a[i].Name, a[j].Name) < 0 }
|
func (a ByProxyStatusResp) Less(i, j int) bool { return strings.Compare(a[i].Name, a[j].Name) < 0 }
|
||||||
|
|
||||||
func NewProxyStatusResp(status *proxy.ProxyStatus) ProxyStatusResp {
|
func NewProxyStatusResp(status *proxy.ProxyStatus, serverAddr string) ProxyStatusResp {
|
||||||
psr := ProxyStatusResp{
|
psr := ProxyStatusResp{
|
||||||
Name: status.Name,
|
Name: status.Name,
|
||||||
Type: status.Type,
|
Type: status.Type,
|
||||||
|
@ -121,18 +120,18 @@ func NewProxyStatusResp(status *proxy.ProxyStatus) ProxyStatusResp {
|
||||||
}
|
}
|
||||||
psr.Plugin = cfg.Plugin
|
psr.Plugin = cfg.Plugin
|
||||||
if status.Err != "" {
|
if status.Err != "" {
|
||||||
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
|
psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
|
||||||
} else {
|
} else {
|
||||||
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
|
psr.RemoteAddr = serverAddr + status.RemoteAddr
|
||||||
}
|
}
|
||||||
case *config.UdpProxyConf:
|
case *config.UdpProxyConf:
|
||||||
if cfg.LocalPort != 0 {
|
if cfg.LocalPort != 0 {
|
||||||
psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
|
psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
|
||||||
}
|
}
|
||||||
if status.Err != "" {
|
if status.Err != "" {
|
||||||
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
|
psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
|
||||||
} else {
|
} else {
|
||||||
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
|
psr.RemoteAddr = serverAddr + status.RemoteAddr
|
||||||
}
|
}
|
||||||
case *config.HttpProxyConf:
|
case *config.HttpProxyConf:
|
||||||
if cfg.LocalPort != 0 {
|
if cfg.LocalPort != 0 {
|
||||||
|
@ -184,17 +183,17 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
|
||||||
for _, status := range ps {
|
for _, status := range ps {
|
||||||
switch status.Type {
|
switch status.Type {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
res.Tcp = append(res.Tcp, NewProxyStatusResp(status))
|
res.Tcp = append(res.Tcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
case "udp":
|
case "udp":
|
||||||
res.Udp = append(res.Udp, NewProxyStatusResp(status))
|
res.Udp = append(res.Udp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
case "http":
|
case "http":
|
||||||
res.Http = append(res.Http, NewProxyStatusResp(status))
|
res.Http = append(res.Http, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
case "https":
|
case "https":
|
||||||
res.Https = append(res.Https, NewProxyStatusResp(status))
|
res.Https = append(res.Https, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
case "stcp":
|
case "stcp":
|
||||||
res.Stcp = append(res.Stcp, NewProxyStatusResp(status))
|
res.Stcp = append(res.Stcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
case "xtcp":
|
case "xtcp":
|
||||||
res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status))
|
res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Sort(ByProxyStatusResp(res.Tcp))
|
sort.Sort(ByProxyStatusResp(res.Tcp))
|
||||||
|
@ -219,14 +218,14 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if g.GlbClientCfg.CfgFile == "" {
|
if svr.cfgFile == "" {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = "frpc has no config file path"
|
res.Msg = "frpc has no config file path"
|
||||||
log.Warn("%s", res.Msg)
|
log.Warn("%s", res.Msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := config.GetRenderedConfFromFile(g.GlbClientCfg.CfgFile)
|
content, err := config.GetRenderedConfFromFile(svr.cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
|
@ -277,7 +276,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// get token from origin content
|
// get token from origin content
|
||||||
token := ""
|
token := ""
|
||||||
b, err := ioutil.ReadFile(g.GlbClientCfg.CfgFile)
|
b, err := ioutil.ReadFile(svr.cfgFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 400
|
res.Code = 400
|
||||||
res.Msg = err.Error()
|
res.Msg = err.Error()
|
||||||
|
@ -316,7 +315,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
content = strings.Join(newRows, "\n")
|
content = strings.Join(newRows, "\n")
|
||||||
|
|
||||||
err = ioutil.WriteFile(g.GlbClientCfg.CfgFile, []byte(content), 0644)
|
err = ioutil.WriteFile(svr.cfgFile, []byte(content), 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
res.Code = 500
|
res.Code = 500
|
||||||
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
|
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client/proxy"
|
"github.com/fatedier/frp/client/proxy"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
@ -65,16 +64,24 @@ type Control struct {
|
||||||
// last time got the Pong message
|
// last time got the Pong message
|
||||||
lastPong time.Time
|
lastPong time.Time
|
||||||
|
|
||||||
|
// The client configuration
|
||||||
|
clientCfg config.ClientCommonConf
|
||||||
|
|
||||||
readerShutdown *shutdown.Shutdown
|
readerShutdown *shutdown.Shutdown
|
||||||
writerShutdown *shutdown.Shutdown
|
writerShutdown *shutdown.Shutdown
|
||||||
msgHandlerShutdown *shutdown.Shutdown
|
msgHandlerShutdown *shutdown.Shutdown
|
||||||
|
|
||||||
|
// The UDP port that the server is listening on
|
||||||
|
serverUDPPort int
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) *Control {
|
func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, clientCfg config.ClientCommonConf,
|
||||||
|
pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, serverUDPPort int) *Control {
|
||||||
|
|
||||||
ctl := &Control{
|
ctl := &Control{
|
||||||
runId: runId,
|
runId: runId,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
|
@ -84,12 +91,14 @@ func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs m
|
||||||
readCh: make(chan msg.Message, 100),
|
readCh: make(chan msg.Message, 100),
|
||||||
closedCh: make(chan struct{}),
|
closedCh: make(chan struct{}),
|
||||||
closedDoneCh: make(chan struct{}),
|
closedDoneCh: make(chan struct{}),
|
||||||
|
clientCfg: clientCfg,
|
||||||
readerShutdown: shutdown.New(),
|
readerShutdown: shutdown.New(),
|
||||||
writerShutdown: shutdown.New(),
|
writerShutdown: shutdown.New(),
|
||||||
msgHandlerShutdown: shutdown.New(),
|
msgHandlerShutdown: shutdown.New(),
|
||||||
|
serverUDPPort: serverUDPPort,
|
||||||
Logger: log.NewPrefixLogger(""),
|
Logger: log.NewPrefixLogger(""),
|
||||||
}
|
}
|
||||||
ctl.pm = proxy.NewProxyManager(ctl.sendCh, runId)
|
ctl.pm = proxy.NewProxyManager(ctl.sendCh, runId, clientCfg, serverUDPPort)
|
||||||
|
|
||||||
ctl.vm = NewVisitorManager(ctl)
|
ctl.vm = NewVisitorManager(ctl)
|
||||||
ctl.vm.Reload(visitorCfgs)
|
ctl.vm.Reload(visitorCfgs)
|
||||||
|
@ -161,7 +170,7 @@ func (ctl *Control) ClosedDoneCh() <-chan struct{} {
|
||||||
|
|
||||||
// connectServer return a new connection to frps
|
// connectServer return a new connection to frps
|
||||||
func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
||||||
if g.GlbClientCfg.TcpMux {
|
if ctl.clientCfg.TcpMux {
|
||||||
stream, errRet := ctl.session.OpenStream()
|
stream, errRet := ctl.session.OpenStream()
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
|
@ -171,13 +180,13 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
||||||
conn = frpNet.WrapConn(stream)
|
conn = frpNet.WrapConn(stream)
|
||||||
} else {
|
} else {
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if g.GlbClientCfg.TLSEnable {
|
if ctl.clientCfg.TLSEnable {
|
||||||
tlsConfig = &tls.Config{
|
tlsConfig = &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
|
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HttpProxy, ctl.clientCfg.Protocol,
|
||||||
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
|
fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.ServerPort), tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.Warn("start new connection to server error: %v", err)
|
ctl.Warn("start new connection to server error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -197,7 +206,7 @@ func (ctl *Control) reader() {
|
||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
defer close(ctl.closedCh)
|
defer close(ctl.closedCh)
|
||||||
|
|
||||||
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbClientCfg.Token))
|
encReader := crypto.NewReader(ctl.conn, []byte(ctl.clientCfg.Token))
|
||||||
for {
|
for {
|
||||||
if m, err := msg.ReadMsg(encReader); err != nil {
|
if m, err := msg.ReadMsg(encReader); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
|
@ -217,7 +226,7 @@ func (ctl *Control) reader() {
|
||||||
// writer writes messages got from sendCh to frps
|
// writer writes messages got from sendCh to frps
|
||||||
func (ctl *Control) writer() {
|
func (ctl *Control) writer() {
|
||||||
defer ctl.writerShutdown.Done()
|
defer ctl.writerShutdown.Done()
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(g.GlbClientCfg.Token))
|
encWriter, err := crypto.NewWriter(ctl.conn, []byte(ctl.clientCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.conn.Error("crypto new writer error: %v", err)
|
ctl.conn.Error("crypto new writer error: %v", err)
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
|
@ -246,7 +255,7 @@ func (ctl *Control) msgHandler() {
|
||||||
}()
|
}()
|
||||||
defer ctl.msgHandlerShutdown.Done()
|
defer ctl.msgHandlerShutdown.Done()
|
||||||
|
|
||||||
hbSend := time.NewTicker(time.Duration(g.GlbClientCfg.HeartBeatInterval) * time.Second)
|
hbSend := time.NewTicker(time.Duration(ctl.clientCfg.HeartBeatInterval) * time.Second)
|
||||||
defer hbSend.Stop()
|
defer hbSend.Stop()
|
||||||
hbCheck := time.NewTicker(time.Second)
|
hbCheck := time.NewTicker(time.Second)
|
||||||
defer hbCheck.Stop()
|
defer hbCheck.Stop()
|
||||||
|
@ -260,7 +269,7 @@ func (ctl *Control) msgHandler() {
|
||||||
ctl.Debug("send heartbeat to server")
|
ctl.Debug("send heartbeat to server")
|
||||||
ctl.sendCh <- &msg.Ping{}
|
ctl.sendCh <- &msg.Ping{}
|
||||||
case <-hbCheck.C:
|
case <-hbCheck.C:
|
||||||
if time.Since(ctl.lastPong) > time.Duration(g.GlbClientCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.Warn("heartbeat timeout")
|
ctl.Warn("heartbeat timeout")
|
||||||
// let reader() stop
|
// let reader() stop
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/plugin"
|
"github.com/fatedier/frp/models/plugin"
|
||||||
|
@ -51,9 +50,11 @@ type Proxy interface {
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
|
func NewProxy(pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
|
||||||
baseProxy := BaseProxy{
|
baseProxy := BaseProxy{
|
||||||
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
|
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
|
||||||
|
clientCfg: clientCfg,
|
||||||
|
serverUDPPort: serverUDPPort,
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.TcpProxyConf:
|
case *config.TcpProxyConf:
|
||||||
|
@ -93,6 +94,8 @@ func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
|
||||||
type BaseProxy struct {
|
type BaseProxy struct {
|
||||||
closed bool
|
closed bool
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
clientCfg config.ClientCommonConf
|
||||||
|
serverUDPPort int
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +125,7 @@ func (pxy *TcpProxy) Close() {
|
||||||
|
|
||||||
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(g.GlbClientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP
|
// HTTP
|
||||||
|
@ -151,7 +154,7 @@ func (pxy *HttpProxy) Close() {
|
||||||
|
|
||||||
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(g.GlbClientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPS
|
// HTTPS
|
||||||
|
@ -180,7 +183,7 @@ func (pxy *HttpsProxy) Close() {
|
||||||
|
|
||||||
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(g.GlbClientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// STCP
|
// STCP
|
||||||
|
@ -209,7 +212,7 @@ func (pxy *StcpProxy) Close() {
|
||||||
|
|
||||||
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(g.GlbClientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// XTCP
|
// XTCP
|
||||||
|
@ -250,7 +253,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
||||||
Sid: natHoleSidMsg.Sid,
|
Sid: natHoleSidMsg.Sid,
|
||||||
}
|
}
|
||||||
raddr, _ := net.ResolveUDPAddr("udp",
|
raddr, _ := net.ResolveUDPAddr("udp",
|
||||||
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
|
fmt.Sprintf("%s:%d", pxy.clientCfg.ServerAddr, pxy.serverUDPPort))
|
||||||
clientConn, err := net.DialUDP("udp", nil, raddr)
|
clientConn, err := net.DialUDP("udp", nil, raddr)
|
||||||
defer clientConn.Close()
|
defer clientConn.Close()
|
||||||
|
|
||||||
|
@ -518,7 +521,7 @@ func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.
|
||||||
DestinationPort: m.DstPort,
|
DestinationPort: m.DstPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.SourceAddress.To16() == nil {
|
if strings.Contains(m.SrcAddr, ".") {
|
||||||
h.TransportProtocol = pp.TCPv4
|
h.TransportProtocol = pp.TCPv4
|
||||||
} else {
|
} else {
|
||||||
h.TransportProtocol = pp.TCPv6
|
h.TransportProtocol = pp.TCPv6
|
||||||
|
|
|
@ -20,15 +20,22 @@ type ProxyManager struct {
|
||||||
closed bool
|
closed bool
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
clientCfg config.ClientCommonConf
|
||||||
|
|
||||||
|
// The UDP port that the server is listening on
|
||||||
|
serverUDPPort int
|
||||||
|
|
||||||
logPrefix string
|
logPrefix string
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyManager(msgSendCh chan (msg.Message), logPrefix string) *ProxyManager {
|
func NewProxyManager(msgSendCh chan (msg.Message), logPrefix string, clientCfg config.ClientCommonConf, serverUDPPort int) *ProxyManager {
|
||||||
return &ProxyManager{
|
return &ProxyManager{
|
||||||
proxies: make(map[string]*ProxyWrapper),
|
proxies: make(map[string]*ProxyWrapper),
|
||||||
sendCh: msgSendCh,
|
sendCh: msgSendCh,
|
||||||
closed: false,
|
closed: false,
|
||||||
|
clientCfg: clientCfg,
|
||||||
|
serverUDPPort: serverUDPPort,
|
||||||
logPrefix: logPrefix,
|
logPrefix: logPrefix,
|
||||||
Logger: log.NewPrefixLogger(logPrefix),
|
Logger: log.NewPrefixLogger(logPrefix),
|
||||||
}
|
}
|
||||||
|
@ -126,7 +133,7 @@ func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
|
||||||
addPxyNames := make([]string, 0)
|
addPxyNames := make([]string, 0)
|
||||||
for name, cfg := range pxyCfgs {
|
for name, cfg := range pxyCfgs {
|
||||||
if _, ok := pm.proxies[name]; !ok {
|
if _, ok := pm.proxies[name]; !ok {
|
||||||
pxy := NewProxyWrapper(cfg, pm.HandleEvent, pm.logPrefix)
|
pxy := NewProxyWrapper(cfg, pm.clientCfg, pm.HandleEvent, pm.logPrefix, pm.serverUDPPort)
|
||||||
pm.proxies[name] = pxy
|
pm.proxies[name] = pxy
|
||||||
addPxyNames = append(addPxyNames, name)
|
addPxyNames = append(addPxyNames, name)
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ type ProxyWrapper struct {
|
||||||
log.Logger
|
log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyWrapper(cfg config.ProxyConf, eventHandler event.EventHandler, logPrefix string) *ProxyWrapper {
|
func NewProxyWrapper(cfg config.ProxyConf, clientCfg config.ClientCommonConf, eventHandler event.EventHandler, logPrefix string, serverUDPPort int) *ProxyWrapper {
|
||||||
baseInfo := cfg.GetBaseInfo()
|
baseInfo := cfg.GetBaseInfo()
|
||||||
pw := &ProxyWrapper{
|
pw := &ProxyWrapper{
|
||||||
ProxyStatus: ProxyStatus{
|
ProxyStatus: ProxyStatus{
|
||||||
|
@ -90,7 +90,7 @@ func NewProxyWrapper(cfg config.ProxyConf, eventHandler event.EventHandler, logP
|
||||||
pw.Trace("enable health check monitor")
|
pw.Trace("enable health check monitor")
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.pxy = NewProxy(pw.Cfg)
|
pw.pxy = NewProxy(pw.Cfg, clientCfg, serverUDPPort)
|
||||||
return pw
|
return pw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
@ -35,6 +34,7 @@ import (
|
||||||
fmux "github.com/hashicorp/yamux"
|
fmux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Service is a client service.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
// uniq id got from frps, attach it in loginMsg
|
// uniq id got from frps, attach it in loginMsg
|
||||||
runId string
|
runId string
|
||||||
|
@ -43,23 +43,27 @@ type Service struct {
|
||||||
ctl *Control
|
ctl *Control
|
||||||
ctlMu sync.RWMutex
|
ctlMu sync.RWMutex
|
||||||
|
|
||||||
|
cfg config.ClientCommonConf
|
||||||
pxyCfgs map[string]config.ProxyConf
|
pxyCfgs map[string]config.ProxyConf
|
||||||
visitorCfgs map[string]config.VisitorConf
|
visitorCfgs map[string]config.VisitorConf
|
||||||
cfgMu sync.RWMutex
|
cfgMu sync.RWMutex
|
||||||
|
|
||||||
|
// The configuration file used to initialize this client, or an empty
|
||||||
|
// string if no configuration file was used.
|
||||||
|
cfgFile string
|
||||||
|
|
||||||
|
// This is configured by the login response from frps
|
||||||
|
serverUDPPort int
|
||||||
|
|
||||||
exit uint32 // 0 means not exit
|
exit uint32 // 0 means not exit
|
||||||
closedCh chan int
|
closedCh chan int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (svr *Service, err error) {
|
// NewService creates a new client service with the given configuration.
|
||||||
// Init assets
|
func NewService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (svr *Service, err error) {
|
||||||
err = assets.Load("")
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("Load assets error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
svr = &Service{
|
svr = &Service{
|
||||||
|
cfg: cfg,
|
||||||
|
cfgFile: cfgFile,
|
||||||
pxyCfgs: pxyCfgs,
|
pxyCfgs: pxyCfgs,
|
||||||
visitorCfgs: visitorCfgs,
|
visitorCfgs: visitorCfgs,
|
||||||
exit: 0,
|
exit: 0,
|
||||||
|
@ -83,14 +87,14 @@ func (svr *Service) Run() error {
|
||||||
|
|
||||||
// if login_fail_exit is true, just exit this program
|
// if login_fail_exit is true, just exit this program
|
||||||
// otherwise sleep a while and try again to connect to server
|
// otherwise sleep a while and try again to connect to server
|
||||||
if g.GlbClientCfg.LoginFailExit {
|
if svr.cfg.LoginFailExit {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// login success
|
// login success
|
||||||
ctl := NewControl(svr.runId, conn, session, svr.pxyCfgs, svr.visitorCfgs)
|
ctl := NewControl(svr.runId, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
|
||||||
ctl.Run()
|
ctl.Run()
|
||||||
svr.ctlMu.Lock()
|
svr.ctlMu.Lock()
|
||||||
svr.ctl = ctl
|
svr.ctl = ctl
|
||||||
|
@ -101,12 +105,18 @@ func (svr *Service) Run() error {
|
||||||
|
|
||||||
go svr.keepControllerWorking()
|
go svr.keepControllerWorking()
|
||||||
|
|
||||||
if g.GlbClientCfg.AdminPort != 0 {
|
if svr.cfg.AdminPort != 0 {
|
||||||
err := svr.RunAdminServer(g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
|
// Init admin server assets
|
||||||
|
err := assets.Load(svr.cfg.AssetsDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Load assets error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = svr.RunAdminServer(svr.cfg.AdminAddr, svr.cfg.AdminPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("run admin server error: %v", err)
|
log.Warn("run admin server error: %v", err)
|
||||||
}
|
}
|
||||||
log.Info("admin server listen on %s:%d", g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
|
log.Info("admin server listen on %s:%d", svr.cfg.AdminAddr, svr.cfg.AdminPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
<-svr.closedCh
|
<-svr.closedCh
|
||||||
|
@ -138,7 +148,7 @@ func (svr *Service) keepControllerWorking() {
|
||||||
// reconnect success, init delayTime
|
// reconnect success, init delayTime
|
||||||
delayTime = time.Second
|
delayTime = time.Second
|
||||||
|
|
||||||
ctl := NewControl(svr.runId, conn, session, svr.pxyCfgs, svr.visitorCfgs)
|
ctl := NewControl(svr.runId, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
|
||||||
ctl.Run()
|
ctl.Run()
|
||||||
svr.ctlMu.Lock()
|
svr.ctlMu.Lock()
|
||||||
svr.ctl = ctl
|
svr.ctl = ctl
|
||||||
|
@ -153,13 +163,13 @@ func (svr *Service) keepControllerWorking() {
|
||||||
// session: if it's not nil, using tcp mux
|
// session: if it's not nil, using tcp mux
|
||||||
func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error) {
|
func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error) {
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if g.GlbClientCfg.TLSEnable {
|
if svr.cfg.TLSEnable {
|
||||||
tlsConfig = &tls.Config{
|
tlsConfig = &tls.Config{
|
||||||
InsecureSkipVerify: true,
|
InsecureSkipVerify: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
|
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HttpProxy, svr.cfg.Protocol,
|
||||||
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
|
fmt.Sprintf("%s:%d", svr.cfg.ServerAddr, svr.cfg.ServerPort), tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -173,7 +183,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if g.GlbClientCfg.TcpMux {
|
if svr.cfg.TcpMux {
|
||||||
fmuxCfg := fmux.DefaultConfig()
|
fmuxCfg := fmux.DefaultConfig()
|
||||||
fmuxCfg.KeepAliveInterval = 20 * time.Second
|
fmuxCfg.KeepAliveInterval = 20 * time.Second
|
||||||
fmuxCfg.LogOutput = ioutil.Discard
|
fmuxCfg.LogOutput = ioutil.Discard
|
||||||
|
@ -194,10 +204,10 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
|
||||||
loginMsg := &msg.Login{
|
loginMsg := &msg.Login{
|
||||||
Arch: runtime.GOARCH,
|
Arch: runtime.GOARCH,
|
||||||
Os: runtime.GOOS,
|
Os: runtime.GOOS,
|
||||||
PoolCount: g.GlbClientCfg.PoolCount,
|
PoolCount: svr.cfg.PoolCount,
|
||||||
User: g.GlbClientCfg.User,
|
User: svr.cfg.User,
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
PrivilegeKey: util.GetAuthKey(g.GlbClientCfg.Token, now),
|
PrivilegeKey: util.GetAuthKey(svr.cfg.Token, now),
|
||||||
Timestamp: now,
|
Timestamp: now,
|
||||||
RunId: svr.runId,
|
RunId: svr.runId,
|
||||||
}
|
}
|
||||||
|
@ -220,7 +230,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
svr.runId = loginRespMsg.RunId
|
svr.runId = loginRespMsg.RunId
|
||||||
g.GlbClientCfg.ServerUdpPort = loginRespMsg.ServerUdpPort
|
svr.serverUDPPort = loginRespMsg.ServerUdpPort
|
||||||
log.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
|
log.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
@ -193,13 +192,13 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
sv.Debug("get a new xtcp user connection")
|
sv.Debug("get a new xtcp user connection")
|
||||||
if g.GlbClientCfg.ServerUdpPort == 0 {
|
if sv.ctl.serverUDPPort == 0 {
|
||||||
sv.Error("xtcp is not supported by server")
|
sv.Error("xtcp is not supported by server")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
raddr, err := net.ResolveUDPAddr("udp",
|
raddr, err := net.ResolveUDPAddr("udp",
|
||||||
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerUdpPort))
|
fmt.Sprintf("%s:%d", sv.ctl.clientCfg.ServerAddr, sv.ctl.serverUDPPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("resolve server UDP addr error")
|
sv.Error("resolve server UDP addr error")
|
||||||
return
|
return
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
_ "github.com/fatedier/frp/assets/frpc/statik"
|
_ "github.com/fatedier/frp/assets/frpc/statik"
|
||||||
"github.com/fatedier/frp/cmd/frpc/sub"
|
"github.com/fatedier/frp/cmd/frpc/sub"
|
||||||
|
|
||||||
|
@ -23,6 +26,7 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
crypto.DefaultSalt = "frp"
|
crypto.DefaultSalt = "frp"
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
sub.Execute()
|
sub.Execute()
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ func init() {
|
||||||
httpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
httpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
httpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
httpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
httpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
httpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
httpCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
httpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
httpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
httpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
httpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
@ -53,7 +54,7 @@ var httpCmd = &cobra.Command{
|
||||||
Use: "http",
|
Use: "http",
|
||||||
Short: "Run frpc with a single http proxy",
|
Short: "Run frpc with a single http proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -86,7 +87,7 @@ var httpCmd = &cobra.Command{
|
||||||
proxyConfs := map[string]config.ProxyConf{
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
cfg.ProxyName: cfg,
|
cfg.ProxyName: cfg,
|
||||||
}
|
}
|
||||||
err = startService(proxyConfs, nil)
|
err = startService(clientCfg, proxyConfs, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -33,6 +33,7 @@ func init() {
|
||||||
httpsCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
httpsCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
httpsCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
httpsCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
httpsCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
httpsCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
httpsCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
httpsCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
httpsCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
httpsCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
httpsCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
@ -49,7 +50,7 @@ var httpsCmd = &cobra.Command{
|
||||||
Use: "https",
|
Use: "https",
|
||||||
Short: "Run frpc with a single https proxy",
|
Short: "Run frpc with a single https proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -78,7 +79,7 @@ var httpsCmd = &cobra.Command{
|
||||||
proxyConfs := map[string]config.ProxyConf{
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
cfg.ProxyName: cfg,
|
cfg.ProxyName: cfg,
|
||||||
}
|
}
|
||||||
err = startService(proxyConfs, nil)
|
err = startService(clientCfg, proxyConfs, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,13 +41,13 @@ var reloadCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = reload()
|
err = reload(clientCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("frpc reload error: %v\n", err)
|
fmt.Printf("frpc reload error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -58,19 +57,19 @@ var reloadCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func reload() error {
|
func reload(clientCfg config.ClientCommonConf) error {
|
||||||
if g.GlbClientCfg.AdminPort == 0 {
|
if clientCfg.AdminPort == 0 {
|
||||||
return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
|
return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://"+
|
req, err := http.NewRequest("GET", "http://"+
|
||||||
g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/reload", nil)
|
clientCfg.AdminAddr+":"+fmt.Sprintf("%d", clientCfg.AdminPort)+"/api/reload", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
|
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
|
||||||
g.GlbClientCfg.AdminPwd))
|
clientCfg.AdminPwd))
|
||||||
|
|
||||||
req.Header.Add("Authorization", authStr)
|
req.Header.Add("Authorization", authStr)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
|
|
@ -28,7 +28,6 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client"
|
"github.com/fatedier/frp/client"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
"github.com/fatedier/frp/utils/version"
|
"github.com/fatedier/frp/utils/version"
|
||||||
|
@ -50,6 +49,7 @@ var (
|
||||||
logLevel string
|
logLevel string
|
||||||
logFile string
|
logFile string
|
||||||
logMaxDays int
|
logMaxDays int
|
||||||
|
disableLogColor bool
|
||||||
|
|
||||||
proxyName string
|
proxyName string
|
||||||
localIp string
|
localIp string
|
||||||
|
@ -113,59 +113,62 @@ func handleSignal(svr *client.Service) {
|
||||||
close(kcpDoneCh)
|
close(kcpDoneCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseClientCommonCfg(fileType int, content string) (err error) {
|
func parseClientCommonCfg(fileType int, content string) (cfg config.ClientCommonConf, err error) {
|
||||||
if fileType == CfgFileTypeIni {
|
if fileType == CfgFileTypeIni {
|
||||||
err = parseClientCommonCfgFromIni(content)
|
cfg, err = parseClientCommonCfgFromIni(content)
|
||||||
} else if fileType == CfgFileTypeCmd {
|
} else if fileType == CfgFileTypeCmd {
|
||||||
err = parseClientCommonCfgFromCmd()
|
cfg, err = parseClientCommonCfgFromCmd()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = g.GlbClientCfg.ClientCommonConf.Check()
|
err = cfg.Check()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseClientCommonCfgFromIni(content string) (err error) {
|
func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error) {
|
||||||
cfg, err := config.UnmarshalClientConfFromIni(&g.GlbClientCfg.ClientCommonConf, content)
|
cfg, err := config.UnmarshalClientConfFromIni(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return config.ClientCommonConf{}, err
|
||||||
}
|
}
|
||||||
g.GlbClientCfg.ClientCommonConf = *cfg
|
return cfg, err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseClientCommonCfgFromCmd() (err error) {
|
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
|
||||||
|
cfg = config.GetDefaultClientConf()
|
||||||
|
|
||||||
strs := strings.Split(serverAddr, ":")
|
strs := strings.Split(serverAddr, ":")
|
||||||
if len(strs) < 2 {
|
if len(strs) < 2 {
|
||||||
err = fmt.Errorf("invalid server_addr")
|
err = fmt.Errorf("invalid server_addr")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if strs[0] != "" {
|
if strs[0] != "" {
|
||||||
g.GlbClientCfg.ServerAddr = strs[0]
|
cfg.ServerAddr = strs[0]
|
||||||
}
|
}
|
||||||
g.GlbClientCfg.ServerPort, err = strconv.Atoi(strs[1])
|
cfg.ServerPort, err = strconv.Atoi(strs[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("invalid server_addr")
|
err = fmt.Errorf("invalid server_addr")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.GlbClientCfg.User = user
|
cfg.User = user
|
||||||
g.GlbClientCfg.Protocol = protocol
|
cfg.Protocol = protocol
|
||||||
g.GlbClientCfg.Token = token
|
cfg.Token = token
|
||||||
g.GlbClientCfg.LogLevel = logLevel
|
cfg.LogLevel = logLevel
|
||||||
g.GlbClientCfg.LogFile = logFile
|
cfg.LogFile = logFile
|
||||||
g.GlbClientCfg.LogMaxDays = int64(logMaxDays)
|
cfg.LogMaxDays = int64(logMaxDays)
|
||||||
if logFile == "console" {
|
if logFile == "console" {
|
||||||
g.GlbClientCfg.LogWay = "console"
|
cfg.LogWay = "console"
|
||||||
} else {
|
} else {
|
||||||
g.GlbClientCfg.LogWay = "file"
|
cfg.LogWay = "file"
|
||||||
}
|
}
|
||||||
return nil
|
cfg.DisableLogColor = disableLogColor
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func runClient(cfgFilePath string) (err error) {
|
func runClient(cfgFilePath string) (err error) {
|
||||||
|
@ -174,26 +177,27 @@ func runClient(cfgFilePath string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.GlbClientCfg.CfgFile = cfgFilePath
|
|
||||||
|
|
||||||
err = parseClientCommonCfg(CfgFileTypeIni, content)
|
cfg, err := parseClientCommonCfg(CfgFileTypeIni, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(g.GlbClientCfg.User, content, g.GlbClientCfg.Start)
|
pxyCfgs, visitorCfgs, err := config.LoadAllConfFromIni(cfg.User, content, cfg.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = startService(pxyCfgs, visitorCfgs)
|
err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (err error) {
|
func startService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (err error) {
|
||||||
log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel, g.GlbClientCfg.LogMaxDays)
|
log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel,
|
||||||
if g.GlbClientCfg.DnsServer != "" {
|
cfg.LogMaxDays, cfg.DisableLogColor)
|
||||||
s := g.GlbClientCfg.DnsServer
|
|
||||||
|
if cfg.DnsServer != "" {
|
||||||
|
s := cfg.DnsServer
|
||||||
if !strings.Contains(s, ":") {
|
if !strings.Contains(s, ":") {
|
||||||
s += ":53"
|
s += ":53"
|
||||||
}
|
}
|
||||||
|
@ -205,19 +209,19 @@ func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]co
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
svr, errRet := client.NewService(pxyCfgs, visitorCfgs)
|
svr, errRet := client.NewService(cfg, pxyCfgs, visitorCfgs, cfgFile)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture the exit signal if we use kcp.
|
// Capture the exit signal if we use kcp.
|
||||||
if g.GlbClientCfg.Protocol == "kcp" {
|
if cfg.Protocol == "kcp" {
|
||||||
go handleSignal(svr)
|
go handleSignal(svr)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = svr.Run()
|
err = svr.Run()
|
||||||
if g.GlbClientCfg.Protocol == "kcp" {
|
if cfg.Protocol == "kcp" {
|
||||||
<-kcpDoneCh
|
<-kcpDoneCh
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client"
|
"github.com/fatedier/frp/client"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,13 +44,13 @@ var statusCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = status()
|
err = status(clientCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("frpc get status error: %v\n", err)
|
fmt.Printf("frpc get status error: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -60,19 +59,19 @@ var statusCmd = &cobra.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func status() error {
|
func status(clientCfg config.ClientCommonConf) error {
|
||||||
if g.GlbClientCfg.AdminPort == 0 {
|
if clientCfg.AdminPort == 0 {
|
||||||
return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
|
return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", "http://"+
|
req, err := http.NewRequest("GET", "http://"+
|
||||||
g.GlbClientCfg.AdminAddr+":"+fmt.Sprintf("%d", g.GlbClientCfg.AdminPort)+"/api/status", nil)
|
clientCfg.AdminAddr+":"+fmt.Sprintf("%d", clientCfg.AdminPort)+"/api/status", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
|
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
|
||||||
g.GlbClientCfg.AdminPwd))
|
clientCfg.AdminPwd))
|
||||||
|
|
||||||
req.Header.Add("Authorization", authStr)
|
req.Header.Add("Authorization", authStr)
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
||||||
stcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
stcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
stcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
stcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
stcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
stcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
stcpCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
stcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
stcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
stcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
stcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
||||||
|
@ -51,7 +52,7 @@ var stcpCmd = &cobra.Command{
|
||||||
Use: "stcp",
|
Use: "stcp",
|
||||||
Short: "Run frpc with a single stcp proxy",
|
Short: "Run frpc with a single stcp proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -103,7 +104,7 @@ var stcpCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = startService(proxyConfs, visitorConfs)
|
err = startService(clientCfg, proxyConfs, visitorConfs, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
||||||
tcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
tcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
tcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
tcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
tcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
tcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
tcpCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
tcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
tcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
tcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
tcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
@ -47,7 +48,7 @@ var tcpCmd = &cobra.Command{
|
||||||
Use: "tcp",
|
Use: "tcp",
|
||||||
Short: "Run frpc with a single tcp proxy",
|
Short: "Run frpc with a single tcp proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -75,7 +76,7 @@ var tcpCmd = &cobra.Command{
|
||||||
proxyConfs := map[string]config.ProxyConf{
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
cfg.ProxyName: cfg,
|
cfg.ProxyName: cfg,
|
||||||
}
|
}
|
||||||
err = startService(proxyConfs, nil)
|
err = startService(clientCfg, proxyConfs, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
||||||
udpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
udpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
udpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
udpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
udpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
udpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
udpCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
udpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
udpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
udpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
udpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
|
||||||
|
@ -47,7 +48,7 @@ var udpCmd = &cobra.Command{
|
||||||
Use: "udp",
|
Use: "udp",
|
||||||
Short: "Run frpc with a single udp proxy",
|
Short: "Run frpc with a single udp proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -75,7 +76,7 @@ var udpCmd = &cobra.Command{
|
||||||
proxyConfs := map[string]config.ProxyConf{
|
proxyConfs := map[string]config.ProxyConf{
|
||||||
cfg.ProxyName: cfg,
|
cfg.ProxyName: cfg,
|
||||||
}
|
}
|
||||||
err = startService(proxyConfs, nil)
|
err = startService(clientCfg, proxyConfs, nil, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -32,6 +32,7 @@ func init() {
|
||||||
xtcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
xtcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
xtcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
xtcpCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "console or file path")
|
||||||
xtcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
xtcpCmd.PersistentFlags().IntVarP(&logMaxDays, "log_max_days", "", 3, "log file reversed days")
|
||||||
|
xtcpCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
xtcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
xtcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
|
||||||
xtcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
xtcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
|
||||||
|
@ -51,7 +52,7 @@ var xtcpCmd = &cobra.Command{
|
||||||
Use: "xtcp",
|
Use: "xtcp",
|
||||||
Short: "Run frpc with a single xtcp proxy",
|
Short: "Run frpc with a single xtcp proxy",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -103,7 +104,7 @@ var xtcpCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = startService(proxyConfs, visitorConfs)
|
err = startService(clientCfg, proxyConfs, visitorConfs, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/golib/crypto"
|
"github.com/fatedier/golib/crypto"
|
||||||
|
|
||||||
_ "github.com/fatedier/frp/assets/frps/statik"
|
_ "github.com/fatedier/frp/assets/frps/statik"
|
||||||
|
@ -22,6 +25,7 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
crypto.DefaultSalt = "frp"
|
crypto.DefaultSalt = "frp"
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
Execute()
|
Execute()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/server"
|
"github.com/fatedier/frp/server"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
@ -53,6 +52,7 @@ var (
|
||||||
logFile string
|
logFile string
|
||||||
logLevel string
|
logLevel string
|
||||||
logMaxDays int64
|
logMaxDays int64
|
||||||
|
disableLogColor bool
|
||||||
token string
|
token string
|
||||||
subDomainHost string
|
subDomainHost string
|
||||||
tcpMux bool
|
tcpMux bool
|
||||||
|
@ -80,6 +80,8 @@ func init() {
|
||||||
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
|
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
|
||||||
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
|
||||||
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
|
rootCmd.PersistentFlags().Int64VarP(&logMaxDays, "log_max_days", "", 3, "log max days")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
rootCmd.PersistentFlags().StringVarP(&token, "token", "t", "", "auth token")
|
||||||
rootCmd.PersistentFlags().StringVarP(&subDomainHost, "subdomain_host", "", "", "subdomain host")
|
rootCmd.PersistentFlags().StringVarP(&subDomainHost, "subdomain_host", "", "", "subdomain host")
|
||||||
rootCmd.PersistentFlags().StringVarP(&allowPorts, "allow_ports", "", "", "allow ports")
|
rootCmd.PersistentFlags().StringVarP(&allowPorts, "allow_ports", "", "", "allow ports")
|
||||||
|
@ -95,6 +97,7 @@ var rootCmd = &cobra.Command{
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cfg config.ServerCommonConf
|
||||||
var err error
|
var err error
|
||||||
if cfgFile != "" {
|
if cfgFile != "" {
|
||||||
var content string
|
var content string
|
||||||
|
@ -102,16 +105,15 @@ var rootCmd = &cobra.Command{
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
g.GlbServerCfg.CfgFile = cfgFile
|
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
|
||||||
err = parseServerCommonCfg(CfgFileTypeIni, content)
|
|
||||||
} else {
|
} else {
|
||||||
err = parseServerCommonCfg(CfgFileTypeCmd, "")
|
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = runServer()
|
err = runServer(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -126,52 +128,51 @@ func Execute() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseServerCommonCfg(fileType int, content string) (err error) {
|
func parseServerCommonCfg(fileType int, content string) (cfg config.ServerCommonConf, err error) {
|
||||||
if fileType == CfgFileTypeIni {
|
if fileType == CfgFileTypeIni {
|
||||||
err = parseServerCommonCfgFromIni(content)
|
cfg, err = parseServerCommonCfgFromIni(content)
|
||||||
} else if fileType == CfgFileTypeCmd {
|
} else if fileType == CfgFileTypeCmd {
|
||||||
err = parseServerCommonCfgFromCmd()
|
cfg, err = parseServerCommonCfgFromCmd()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = g.GlbServerCfg.ServerCommonConf.Check()
|
err = cfg.Check()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
config.InitServerCfg(&g.GlbServerCfg.ServerCommonConf)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseServerCommonCfgFromIni(content string) (err error) {
|
func parseServerCommonCfgFromIni(content string) (config.ServerCommonConf, error) {
|
||||||
cfg, err := config.UnmarshalServerConfFromIni(&g.GlbServerCfg.ServerCommonConf, content)
|
cfg, err := config.UnmarshalServerConfFromIni(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return config.ServerCommonConf{}, err
|
||||||
}
|
}
|
||||||
g.GlbServerCfg.ServerCommonConf = *cfg
|
return cfg, nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseServerCommonCfgFromCmd() (err error) {
|
func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
|
||||||
g.GlbServerCfg.BindAddr = bindAddr
|
cfg = config.GetDefaultServerConf()
|
||||||
g.GlbServerCfg.BindPort = bindPort
|
|
||||||
g.GlbServerCfg.BindUdpPort = bindUdpPort
|
cfg.BindAddr = bindAddr
|
||||||
g.GlbServerCfg.KcpBindPort = kcpBindPort
|
cfg.BindPort = bindPort
|
||||||
g.GlbServerCfg.ProxyBindAddr = proxyBindAddr
|
cfg.BindUdpPort = bindUdpPort
|
||||||
g.GlbServerCfg.VhostHttpPort = vhostHttpPort
|
cfg.KcpBindPort = kcpBindPort
|
||||||
g.GlbServerCfg.VhostHttpsPort = vhostHttpsPort
|
cfg.ProxyBindAddr = proxyBindAddr
|
||||||
g.GlbServerCfg.VhostHttpTimeout = vhostHttpTimeout
|
cfg.VhostHttpPort = vhostHttpPort
|
||||||
g.GlbServerCfg.DashboardAddr = dashboardAddr
|
cfg.VhostHttpsPort = vhostHttpsPort
|
||||||
g.GlbServerCfg.DashboardPort = dashboardPort
|
cfg.VhostHttpTimeout = vhostHttpTimeout
|
||||||
g.GlbServerCfg.DashboardUser = dashboardUser
|
cfg.DashboardAddr = dashboardAddr
|
||||||
g.GlbServerCfg.DashboardPwd = dashboardPwd
|
cfg.DashboardPort = dashboardPort
|
||||||
g.GlbServerCfg.LogFile = logFile
|
cfg.DashboardUser = dashboardUser
|
||||||
g.GlbServerCfg.LogLevel = logLevel
|
cfg.DashboardPwd = dashboardPwd
|
||||||
g.GlbServerCfg.LogMaxDays = logMaxDays
|
cfg.LogFile = logFile
|
||||||
g.GlbServerCfg.Token = token
|
cfg.LogLevel = logLevel
|
||||||
g.GlbServerCfg.SubDomainHost = subDomainHost
|
cfg.LogMaxDays = logMaxDays
|
||||||
|
cfg.Token = token
|
||||||
|
cfg.SubDomainHost = subDomainHost
|
||||||
if len(allowPorts) > 0 {
|
if len(allowPorts) > 0 {
|
||||||
// e.g. 1000-2000,2001,2002,3000-4000
|
// e.g. 1000-2000,2001,2002,3000-4000
|
||||||
ports, errRet := util.ParseRangeNumbers(allowPorts)
|
ports, errRet := util.ParseRangeNumbers(allowPorts)
|
||||||
|
@ -181,28 +182,27 @@ func parseServerCommonCfgFromCmd() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, port := range ports {
|
for _, port := range ports {
|
||||||
g.GlbServerCfg.AllowPorts[int(port)] = struct{}{}
|
cfg.AllowPorts[int(port)] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.GlbServerCfg.MaxPortsPerClient = maxPortsPerClient
|
cfg.MaxPortsPerClient = maxPortsPerClient
|
||||||
|
|
||||||
if logFile == "console" {
|
if logFile == "console" {
|
||||||
g.GlbServerCfg.LogWay = "console"
|
cfg.LogWay = "console"
|
||||||
} else {
|
} else {
|
||||||
g.GlbServerCfg.LogWay = "file"
|
cfg.LogWay = "file"
|
||||||
}
|
}
|
||||||
|
cfg.DisableLogColor = disableLogColor
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func runServer() (err error) {
|
func runServer(cfg config.ServerCommonConf) (err error) {
|
||||||
log.InitLog(g.GlbServerCfg.LogWay, g.GlbServerCfg.LogFile, g.GlbServerCfg.LogLevel,
|
log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel, cfg.LogMaxDays, cfg.DisableLogColor)
|
||||||
g.GlbServerCfg.LogMaxDays)
|
svr, err := server.NewService(cfg)
|
||||||
svr, err := server.NewService()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("Start frps success")
|
log.Info("Start frps success")
|
||||||
server.ServerService = svr
|
|
||||||
svr.Run()
|
svr.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@ log_level = info
|
||||||
|
|
||||||
log_max_days = 3
|
log_max_days = 3
|
||||||
|
|
||||||
|
# disable log colors when log_file is console, default is false
|
||||||
|
disable_log_color = false
|
||||||
|
|
||||||
# for authentication
|
# for authentication
|
||||||
token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
|
@ -26,6 +29,8 @@ admin_addr = 127.0.0.1
|
||||||
admin_port = 7400
|
admin_port = 7400
|
||||||
admin_user = admin
|
admin_user = admin
|
||||||
admin_pwd = admin
|
admin_pwd = admin
|
||||||
|
# Admin assets directory. By default, these assets are bundled with frpc.
|
||||||
|
# assets_dir = ./static
|
||||||
|
|
||||||
# connections will be established in advance, default value is zero
|
# connections will be established in advance, default value is zero
|
||||||
pool_count = 5
|
pool_count = 5
|
||||||
|
@ -198,6 +203,7 @@ plugin_local_addr = 127.0.0.1:80
|
||||||
plugin_crt_path = ./server.crt
|
plugin_crt_path = ./server.crt
|
||||||
plugin_key_path = ./server.key
|
plugin_key_path = ./server.key
|
||||||
plugin_host_header_rewrite = 127.0.0.1
|
plugin_host_header_rewrite = 127.0.0.1
|
||||||
|
plugin_header_X-From-Where = frp
|
||||||
|
|
||||||
[secret_tcp]
|
[secret_tcp]
|
||||||
# If the type is secret tcp, remote_port is useless
|
# If the type is secret tcp, remote_port is useless
|
||||||
|
|
|
@ -43,6 +43,9 @@ log_level = info
|
||||||
|
|
||||||
log_max_days = 3
|
log_max_days = 3
|
||||||
|
|
||||||
|
# disable log colors when log_file is console, default is false
|
||||||
|
disable_log_color = false
|
||||||
|
|
||||||
# auth token
|
# auth token
|
||||||
token = 12345678
|
token = 12345678
|
||||||
|
|
||||||
|
|
32
g/g.go
32
g/g.go
|
@ -1,32 +0,0 @@
|
||||||
package g
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/fatedier/frp/models/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
GlbClientCfg *ClientCfg
|
|
||||||
GlbServerCfg *ServerCfg
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
GlbClientCfg = &ClientCfg{
|
|
||||||
ClientCommonConf: *config.GetDefaultClientConf(),
|
|
||||||
}
|
|
||||||
GlbServerCfg = &ServerCfg{
|
|
||||||
ServerCommonConf: *config.GetDefaultServerConf(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClientCfg struct {
|
|
||||||
config.ClientCommonConf
|
|
||||||
|
|
||||||
CfgFile string
|
|
||||||
ServerUdpPort int // this is configured by login response from frps
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerCfg struct {
|
|
||||||
config.ServerCommonConf
|
|
||||||
|
|
||||||
CfgFile string
|
|
||||||
}
|
|
2
go.sum
2
go.sum
|
@ -1,5 +1,6 @@
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
|
||||||
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
||||||
|
@ -27,6 +28,7 @@ github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc h1:lNOt1SMsgHX
|
||||||
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY=
|
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY=
|
||||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rakyll/statik v0.1.1 h1:fCLHsIMajHqD5RKigbFXpvX3dN7c80Pm12+NCrI3kvg=
|
github.com/rakyll/statik v0.1.1 h1:fCLHsIMajHqD5RKigbFXpvX3dN7c80Pm12+NCrI3kvg=
|
||||||
github.com/rakyll/statik v0.1.1/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
|
github.com/rakyll/statik v0.1.1/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
|
||||||
|
|
|
@ -23,34 +23,103 @@ import (
|
||||||
ini "github.com/vaughan0/go-ini"
|
ini "github.com/vaughan0/go-ini"
|
||||||
)
|
)
|
||||||
|
|
||||||
// client common config
|
// ClientCommonConf contains information for a client service. It is
|
||||||
|
// recommended to use GetDefaultClientConf instead of creating this object
|
||||||
|
// directly, so that all unspecified fields have reasonable default values.
|
||||||
type ClientCommonConf struct {
|
type ClientCommonConf struct {
|
||||||
|
// ServerAddr specifies the address of the server to connect to. By
|
||||||
|
// default, this value is "0.0.0.0".
|
||||||
ServerAddr string `json:"server_addr"`
|
ServerAddr string `json:"server_addr"`
|
||||||
|
// ServerPort specifies the port to connect to the server on. By default,
|
||||||
|
// this value is 7000.
|
||||||
ServerPort int `json:"server_port"`
|
ServerPort int `json:"server_port"`
|
||||||
|
// HttpProxy specifies a proxy address to connect to the server through. If
|
||||||
|
// this value is "", the server will be connected to directly. By default,
|
||||||
|
// this value is read from the "http_proxy" environment variable.
|
||||||
HttpProxy string `json:"http_proxy"`
|
HttpProxy string `json:"http_proxy"`
|
||||||
|
// LogFile specifies a file where logs will be written to. This value will
|
||||||
|
// only be used if LogWay is set appropriately. By default, this value is
|
||||||
|
// "console".
|
||||||
LogFile string `json:"log_file"`
|
LogFile string `json:"log_file"`
|
||||||
|
// LogWay specifies the way logging is managed. Valid values are "console"
|
||||||
|
// or "file". If "console" is used, logs will be printed to stdout. If
|
||||||
|
// "file" is used, logs will be printed to LogFile. By default, this value
|
||||||
|
// is "console".
|
||||||
LogWay string `json:"log_way"`
|
LogWay string `json:"log_way"`
|
||||||
|
// LogLevel specifies the minimum log level. Valid values are "trace",
|
||||||
|
// "debug", "info", "warn", and "error". By default, this value is "info".
|
||||||
LogLevel string `json:"log_level"`
|
LogLevel string `json:"log_level"`
|
||||||
|
// LogMaxDays specifies the maximum number of days to store log information
|
||||||
|
// before deletion. This is only used if LogWay == "file". By default, this
|
||||||
|
// value is 0.
|
||||||
LogMaxDays int64 `json:"log_max_days"`
|
LogMaxDays int64 `json:"log_max_days"`
|
||||||
|
// DisableLogColor disables log colors when LogWay == "console" when set to
|
||||||
|
// true. By default, this value is false.
|
||||||
|
DisableLogColor bool `json:"disable_log_color"`
|
||||||
|
// Token specifies the authorization token used to create keys to be sent
|
||||||
|
// to the server. The server must have a matching token for authorization
|
||||||
|
// to succeed. By default, this value is "".
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
// AdminAddr specifies the address that the admin server binds to. By
|
||||||
|
// default, this value is "127.0.0.1".
|
||||||
AdminAddr string `json:"admin_addr"`
|
AdminAddr string `json:"admin_addr"`
|
||||||
|
// AdminPort specifies the port for the admin server to listen on. If this
|
||||||
|
// value is 0, the admin server will not be started. By default, this value
|
||||||
|
// is 0.
|
||||||
AdminPort int `json:"admin_port"`
|
AdminPort int `json:"admin_port"`
|
||||||
|
// AdminUser specifies the username that the admin server will use for
|
||||||
|
// login. By default, this value is "admin".
|
||||||
AdminUser string `json:"admin_user"`
|
AdminUser string `json:"admin_user"`
|
||||||
|
// AdminPwd specifies the password that the admin server will use for
|
||||||
|
// login. By default, this value is "admin".
|
||||||
AdminPwd string `json:"admin_pwd"`
|
AdminPwd string `json:"admin_pwd"`
|
||||||
|
// AssetsDir specifies the local directory that the admin server will load
|
||||||
|
// resources from. If this value is "", assets will be loaded from the
|
||||||
|
// bundled executable using statik. By default, this value is "".
|
||||||
|
AssetsDir string `json:"assets_dir"`
|
||||||
|
// PoolCount specifies the number of connections the client will make to
|
||||||
|
// the server in advance. By default, this value is 0.
|
||||||
PoolCount int `json:"pool_count"`
|
PoolCount int `json:"pool_count"`
|
||||||
|
// TcpMux toggles TCP stream multiplexing. This allows multiple requests
|
||||||
|
// from a client to share a single TCP connection. If this value is true,
|
||||||
|
// the server must have TCP multiplexing enabled as well. By default, this
|
||||||
|
// value is true.
|
||||||
TcpMux bool `json:"tcp_mux"`
|
TcpMux bool `json:"tcp_mux"`
|
||||||
|
// User specifies a prefix for proxy names to distinguish them from other
|
||||||
|
// clients. If this value is not "", proxy names will automatically be
|
||||||
|
// changed to "{user}.{proxy_name}". By default, this value is "".
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
|
// DnsServer specifies a DNS server address for FRPC to use. If this value
|
||||||
|
// is "", the default DNS will be used. By default, this value is "".
|
||||||
DnsServer string `json:"dns_server"`
|
DnsServer string `json:"dns_server"`
|
||||||
|
// LoginFailExit controls whether or not the client should exit after a
|
||||||
|
// failed login attempt. If false, the client will retry until a login
|
||||||
|
// attempt succeeds. By default, this value is true.
|
||||||
LoginFailExit bool `json:"login_fail_exit"`
|
LoginFailExit bool `json:"login_fail_exit"`
|
||||||
|
// Start specifies a set of enabled proxies by name. If this set is empty,
|
||||||
|
// all supplied proxies are enabled. By default, this value is an empty
|
||||||
|
// set.
|
||||||
Start map[string]struct{} `json:"start"`
|
Start map[string]struct{} `json:"start"`
|
||||||
|
// Protocol specifies the protocol to use when interacting with the server.
|
||||||
|
// Valid values are "tcp", "kcp", and "websocket". By default, this value
|
||||||
|
// is "tcp".
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
|
// TLSEnable specifies whether or not TLS should be used when communicating
|
||||||
|
// with the server.
|
||||||
TLSEnable bool `json:"tls_enable"`
|
TLSEnable bool `json:"tls_enable"`
|
||||||
|
// HeartBeatInterval specifies at what interval heartbeats are sent to the
|
||||||
|
// server, in seconds. It is not recommended to change this value. By
|
||||||
|
// default, this value is 30.
|
||||||
HeartBeatInterval int64 `json:"heartbeat_interval"`
|
HeartBeatInterval int64 `json:"heartbeat_interval"`
|
||||||
|
// HeartBeatTimeout specifies the maximum allowed heartbeat response delay
|
||||||
|
// before the connection is terminated, in seconds. It is not recommended
|
||||||
|
// to change this value. By default, this value is 90.
|
||||||
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
|
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultClientConf() *ClientCommonConf {
|
// GetDefaultClientConf returns a client configuration with default values.
|
||||||
return &ClientCommonConf{
|
func GetDefaultClientConf() ClientCommonConf {
|
||||||
|
return ClientCommonConf{
|
||||||
ServerAddr: "0.0.0.0",
|
ServerAddr: "0.0.0.0",
|
||||||
ServerPort: 7000,
|
ServerPort: 7000,
|
||||||
HttpProxy: os.Getenv("http_proxy"),
|
HttpProxy: os.Getenv("http_proxy"),
|
||||||
|
@ -58,11 +127,13 @@ func GetDefaultClientConf() *ClientCommonConf {
|
||||||
LogWay: "console",
|
LogWay: "console",
|
||||||
LogLevel: "info",
|
LogLevel: "info",
|
||||||
LogMaxDays: 3,
|
LogMaxDays: 3,
|
||||||
|
DisableLogColor: false,
|
||||||
Token: "",
|
Token: "",
|
||||||
AdminAddr: "127.0.0.1",
|
AdminAddr: "127.0.0.1",
|
||||||
AdminPort: 0,
|
AdminPort: 0,
|
||||||
AdminUser: "",
|
AdminUser: "",
|
||||||
AdminPwd: "",
|
AdminPwd: "",
|
||||||
|
AssetsDir: "",
|
||||||
PoolCount: 1,
|
PoolCount: 1,
|
||||||
TcpMux: true,
|
TcpMux: true,
|
||||||
User: "",
|
User: "",
|
||||||
|
@ -76,16 +147,12 @@ func GetDefaultClientConf() *ClientCommonConf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (cfg *ClientCommonConf, err error) {
|
func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error) {
|
||||||
cfg = defaultCfg
|
|
||||||
if cfg == nil {
|
|
||||||
cfg = GetDefaultClientConf()
|
cfg = GetDefaultClientConf()
|
||||||
}
|
|
||||||
|
|
||||||
conf, err := ini.Load(strings.NewReader(content))
|
conf, err := ini.Load(strings.NewReader(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("parse ini conf file error: %v", err)
|
return ClientCommonConf{}, fmt.Errorf("parse ini conf file error: %v", err)
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -106,6 +173,10 @@ func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (c
|
||||||
cfg.ServerPort = int(v)
|
cfg.ServerPort = int(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tmpStr, ok = conf.Get("common", "disable_log_color"); ok && tmpStr == "true" {
|
||||||
|
cfg.DisableLogColor = true
|
||||||
|
}
|
||||||
|
|
||||||
if tmpStr, ok = conf.Get("common", "http_proxy"); ok {
|
if tmpStr, ok = conf.Get("common", "http_proxy"); ok {
|
||||||
cfg.HttpProxy = tmpStr
|
cfg.HttpProxy = tmpStr
|
||||||
}
|
}
|
||||||
|
@ -154,6 +225,10 @@ func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (c
|
||||||
cfg.AdminPwd = tmpStr
|
cfg.AdminPwd = tmpStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tmpStr, ok = conf.Get("common", "assets_dir"); ok {
|
||||||
|
cfg.AssetsDir = tmpStr
|
||||||
|
}
|
||||||
|
|
||||||
if tmpStr, ok = conf.Get("common", "pool_count"); ok {
|
if tmpStr, ok = conf.Get("common", "pool_count"); ok {
|
||||||
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
if v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
|
||||||
cfg.PoolCount = int(v)
|
cfg.PoolCount = int(v)
|
||||||
|
|
|
@ -58,11 +58,11 @@ type ProxyConf interface {
|
||||||
UnmarshalFromIni(prefix string, name string, conf ini.Section) error
|
UnmarshalFromIni(prefix string, name string, conf ini.Section) error
|
||||||
MarshalToMsg(pMsg *msg.NewProxy)
|
MarshalToMsg(pMsg *msg.NewProxy)
|
||||||
CheckForCli() error
|
CheckForCli() error
|
||||||
CheckForSvr() error
|
CheckForSvr(serverCfg ServerCommonConf) error
|
||||||
Compare(conf ProxyConf) bool
|
Compare(conf ProxyConf) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyConfFromMsg(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
func NewProxyConfFromMsg(pMsg *msg.NewProxy, serverCfg ServerCommonConf) (cfg ProxyConf, err error) {
|
||||||
if pMsg.ProxyType == "" {
|
if pMsg.ProxyType == "" {
|
||||||
pMsg.ProxyType = consts.TcpProxy
|
pMsg.ProxyType = consts.TcpProxy
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func NewProxyConfFromMsg(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg.UnmarshalFromMsg(pMsg)
|
cfg.UnmarshalFromMsg(pMsg)
|
||||||
err = cfg.CheckForSvr()
|
err = cfg.CheckForSvr(serverCfg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,17 +97,33 @@ func NewProxyConfFromIni(prefix string, name string, section ini.Section) (cfg P
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseProxy info
|
// BaseProxyConf provides configuration info that is common to all proxy types.
|
||||||
type BaseProxyConf struct {
|
type BaseProxyConf struct {
|
||||||
|
// ProxyName is the name of this proxy.
|
||||||
ProxyName string `json:"proxy_name"`
|
ProxyName string `json:"proxy_name"`
|
||||||
|
// ProxyType specifies the type of this proxy. Valid values include "tcp",
|
||||||
|
// "udp", "http", "https", "stcp", and "xtcp". By default, this value is
|
||||||
|
// "tcp".
|
||||||
ProxyType string `json:"proxy_type"`
|
ProxyType string `json:"proxy_type"`
|
||||||
|
|
||||||
|
// UseEncryption controls whether or not communication with the server will
|
||||||
|
// be encrypted. Encryption is done using the tokens supplied in the server
|
||||||
|
// and client configuration. By default, this value is false.
|
||||||
UseEncryption bool `json:"use_encryption"`
|
UseEncryption bool `json:"use_encryption"`
|
||||||
|
// UseCompression controls whether or not communication with the server
|
||||||
|
// will be compressed. By default, this value is false.
|
||||||
UseCompression bool `json:"use_compression"`
|
UseCompression bool `json:"use_compression"`
|
||||||
|
// Group specifies which group the proxy is a part of. The server will use
|
||||||
|
// this information to load balance proxies in the same group. If the value
|
||||||
|
// is "", this proxy will not be in a group. By default, this value is "".
|
||||||
Group string `json:"group"`
|
Group string `json:"group"`
|
||||||
|
// GroupKey specifies a group key, which should be the same among proxies
|
||||||
|
// of the same group. By default, this value is "".
|
||||||
GroupKey string `json:"group_key"`
|
GroupKey string `json:"group_key"`
|
||||||
|
|
||||||
// only used for client
|
// ProxyProtocolVersion specifies which protocol version to use. Valid
|
||||||
|
// values include "v1", "v2", and "". If the value is "", a protocol
|
||||||
|
// version will be automatically selected. By default, this value is "".
|
||||||
ProxyProtocolVersion string `json:"proxy_protocol_version"`
|
ProxyProtocolVersion string `json:"proxy_protocol_version"`
|
||||||
LocalSvrConf
|
LocalSvrConf
|
||||||
HealthCheckConf
|
HealthCheckConf
|
||||||
|
@ -308,21 +324,21 @@ func (cfg *DomainConf) checkForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *DomainConf) checkForSvr() (err error) {
|
func (cfg *DomainConf) checkForSvr(serverCfg ServerCommonConf) (err error) {
|
||||||
if err = cfg.check(); err != nil {
|
if err = cfg.check(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, domain := range cfg.CustomDomains {
|
for _, domain := range cfg.CustomDomains {
|
||||||
if subDomainHost != "" && len(strings.Split(subDomainHost, ".")) < len(strings.Split(domain, ".")) {
|
if serverCfg.SubDomainHost != "" && len(strings.Split(serverCfg.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
|
||||||
if strings.Contains(domain, subDomainHost) {
|
if strings.Contains(domain, serverCfg.SubDomainHost) {
|
||||||
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, subDomainHost)
|
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, serverCfg.SubDomainHost)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.SubDomain != "" {
|
if cfg.SubDomain != "" {
|
||||||
if subDomainHost == "" {
|
if serverCfg.SubDomainHost == "" {
|
||||||
return fmt.Errorf("subdomain is not supported because this feature is not enabled in remote frps")
|
return fmt.Errorf("subdomain is not supported because this feature is not enabled in remote frps")
|
||||||
}
|
}
|
||||||
if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") {
|
if strings.Contains(cfg.SubDomain, ".") || strings.Contains(cfg.SubDomain, "*") {
|
||||||
|
@ -332,12 +348,20 @@ func (cfg *DomainConf) checkForSvr() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local service info
|
// LocalSvrConf configures what location the client will proxy to, or what
|
||||||
|
// plugin will be used.
|
||||||
type LocalSvrConf struct {
|
type LocalSvrConf struct {
|
||||||
|
// LocalIp specifies the IP address or host name to proxy to.
|
||||||
LocalIp string `json:"local_ip"`
|
LocalIp string `json:"local_ip"`
|
||||||
|
// LocalPort specifies the port to proxy to.
|
||||||
LocalPort int `json:"local_port"`
|
LocalPort int `json:"local_port"`
|
||||||
|
|
||||||
|
// Plugin specifies what plugin should be used for proxying. If this value
|
||||||
|
// is set, the LocalIp and LocalPort values will be ignored. By default,
|
||||||
|
// this value is "".
|
||||||
Plugin string `json:"plugin"`
|
Plugin string `json:"plugin"`
|
||||||
|
// PluginParams specify parameters to be passed to the plugin, if one is
|
||||||
|
// being used. By default, this value is an empty map.
|
||||||
PluginParams map[string]string `json:"plugin_params"`
|
PluginParams map[string]string `json:"plugin_params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,15 +423,35 @@ func (cfg *LocalSvrConf) checkForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Health check info
|
// HealthCheckConf configures health checking. This can be useful for load
|
||||||
|
// balancing purposes to detect and remove proxies to failing services.
|
||||||
type HealthCheckConf struct {
|
type HealthCheckConf struct {
|
||||||
|
// HealthCheckType specifies what protocol to use for health checking.
|
||||||
|
// Valid values include "tcp", "http", and "". If this value is "", health
|
||||||
|
// checking will not be performed. By default, this value is "".
|
||||||
|
//
|
||||||
|
// If the type is "tcp", a connection will be attempted to the target
|
||||||
|
// server. If a connection cannot be established, the health check fails.
|
||||||
|
//
|
||||||
|
// If the type is "http", a GET request will be made to the endpoint
|
||||||
|
// specified by HealthCheckUrl. If the response is not a 200, the health
|
||||||
|
// check fails.
|
||||||
HealthCheckType string `json:"health_check_type"` // tcp | http
|
HealthCheckType string `json:"health_check_type"` // tcp | http
|
||||||
|
// HealthCheckTimeoutS specifies the number of seconds to wait for a health
|
||||||
|
// check attempt to connect. If the timeout is reached, this counts as a
|
||||||
|
// health check failure. By default, this value is 3.
|
||||||
HealthCheckTimeoutS int `json:"health_check_timeout_s"`
|
HealthCheckTimeoutS int `json:"health_check_timeout_s"`
|
||||||
|
// HealthCheckMaxFailed specifies the number of allowed failures before the
|
||||||
|
// proxy is stopped. By default, this value is 1.
|
||||||
HealthCheckMaxFailed int `json:"health_check_max_failed"`
|
HealthCheckMaxFailed int `json:"health_check_max_failed"`
|
||||||
|
// HealthCheckIntervalS specifies the time in seconds between health
|
||||||
|
// checks. By default, this value is 10.
|
||||||
HealthCheckIntervalS int `json:"health_check_interval_s"`
|
HealthCheckIntervalS int `json:"health_check_interval_s"`
|
||||||
|
// HealthCheckUrl specifies the address to send health checks to if the
|
||||||
|
// health check type is "http".
|
||||||
HealthCheckUrl string `json:"health_check_url"`
|
HealthCheckUrl string `json:"health_check_url"`
|
||||||
|
// HealthCheckAddr specifies the address to connect to if the health check
|
||||||
// local_ip + local_port
|
// type is "tcp".
|
||||||
HealthCheckAddr string `json:"-"`
|
HealthCheckAddr string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +548,7 @@ func (cfg *TcpProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *TcpProxyConf) CheckForSvr() error { return nil }
|
func (cfg *TcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { return nil }
|
||||||
|
|
||||||
// UDP
|
// UDP
|
||||||
type UdpProxyConf struct {
|
type UdpProxyConf struct {
|
||||||
|
@ -552,7 +596,7 @@ func (cfg *UdpProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *UdpProxyConf) CheckForSvr() error { return nil }
|
func (cfg *UdpProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { return nil }
|
||||||
|
|
||||||
// HTTP
|
// HTTP
|
||||||
type HttpProxyConf struct {
|
type HttpProxyConf struct {
|
||||||
|
@ -657,11 +701,11 @@ func (cfg *HttpProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpProxyConf) CheckForSvr() (err error) {
|
func (cfg *HttpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
|
||||||
if vhostHttpPort == 0 {
|
if serverCfg.VhostHttpPort == 0 {
|
||||||
return fmt.Errorf("type [http] not support when vhost_http_port is not set")
|
return fmt.Errorf("type [http] not support when vhost_http_port is not set")
|
||||||
}
|
}
|
||||||
if err = cfg.DomainConf.checkForSvr(); err != nil {
|
if err = cfg.DomainConf.checkForSvr(serverCfg); err != nil {
|
||||||
err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err)
|
err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -717,11 +761,11 @@ func (cfg *HttpsProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *HttpsProxyConf) CheckForSvr() (err error) {
|
func (cfg *HttpsProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
|
||||||
if vhostHttpsPort == 0 {
|
if serverCfg.VhostHttpsPort == 0 {
|
||||||
return fmt.Errorf("type [https] not support when vhost_https_port is not set")
|
return fmt.Errorf("type [https] not support when vhost_https_port is not set")
|
||||||
}
|
}
|
||||||
if err = cfg.DomainConf.checkForSvr(); err != nil {
|
if err = cfg.DomainConf.checkForSvr(serverCfg); err != nil {
|
||||||
err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err)
|
err = fmt.Errorf("proxy [%s] domain conf check error: %v", cfg.ProxyName, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -790,7 +834,7 @@ func (cfg *StcpProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *StcpProxyConf) CheckForSvr() (err error) {
|
func (cfg *StcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,7 +901,7 @@ func (cfg *XtcpProxyConf) CheckForCli() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *XtcpProxyConf) CheckForSvr() (err error) {
|
func (cfg *XtcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,62 +24,122 @@ import (
|
||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// ServerCommonConf contains information for a server service. It is
|
||||||
// server global configure used for generate proxy conf used in frps
|
// recommended to use GetDefaultServerConf instead of creating this object
|
||||||
proxyBindAddr string
|
// directly, so that all unspecified fields have reasonable default values.
|
||||||
subDomainHost string
|
|
||||||
vhostHttpPort int
|
|
||||||
vhostHttpsPort int
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitServerCfg(cfg *ServerCommonConf) {
|
|
||||||
proxyBindAddr = cfg.ProxyBindAddr
|
|
||||||
subDomainHost = cfg.SubDomainHost
|
|
||||||
vhostHttpPort = cfg.VhostHttpPort
|
|
||||||
vhostHttpsPort = cfg.VhostHttpsPort
|
|
||||||
}
|
|
||||||
|
|
||||||
// common config
|
|
||||||
type ServerCommonConf struct {
|
type ServerCommonConf struct {
|
||||||
|
// BindAddr specifies the address that the server binds to. By default,
|
||||||
|
// this value is "0.0.0.0".
|
||||||
BindAddr string `json:"bind_addr"`
|
BindAddr string `json:"bind_addr"`
|
||||||
|
// BindPort specifies the port that the server listens on. By default, this
|
||||||
|
// value is 7000.
|
||||||
BindPort int `json:"bind_port"`
|
BindPort int `json:"bind_port"`
|
||||||
|
// BindUdpPort specifies the UDP port that the server listens on. If this
|
||||||
|
// value is 0, the server will not listen for UDP connections. By default,
|
||||||
|
// this value is 0
|
||||||
BindUdpPort int `json:"bind_udp_port"`
|
BindUdpPort int `json:"bind_udp_port"`
|
||||||
|
// BindKcpPort specifies the KCP port that the server listens on. If this
|
||||||
|
// value is 0, the server will not listen for KCP connections. By default,
|
||||||
|
// this value is 0.
|
||||||
KcpBindPort int `json:"kcp_bind_port"`
|
KcpBindPort int `json:"kcp_bind_port"`
|
||||||
|
// ProxyBindAddr specifies the address that the proxy binds to. This value
|
||||||
|
// may be the same as BindAddr. By default, this value is "0.0.0.0".
|
||||||
ProxyBindAddr string `json:"proxy_bind_addr"`
|
ProxyBindAddr string `json:"proxy_bind_addr"`
|
||||||
|
|
||||||
// If VhostHttpPort equals 0, don't listen a public port for http protocol.
|
// VhostHttpPort specifies the port that the server listens for HTTP Vhost
|
||||||
|
// requests. If this value is 0, the server will not listen for HTTP
|
||||||
|
// requests. By default, this value is 0.
|
||||||
VhostHttpPort int `json:"vhost_http_port"`
|
VhostHttpPort int `json:"vhost_http_port"`
|
||||||
|
|
||||||
// if VhostHttpsPort equals 0, don't listen a public port for https protocol
|
// VhostHttpsPort specifies the port that the server listens for HTTPS
|
||||||
|
// Vhost requests. If this value is 0, the server will not listen for HTTPS
|
||||||
|
// requests. By default, this value is 0.
|
||||||
VhostHttpsPort int `json:"vhost_https_port"`
|
VhostHttpsPort int `json:"vhost_https_port"`
|
||||||
|
|
||||||
|
// VhostHttpTimeout specifies the response header timeout for the Vhost
|
||||||
|
// HTTP server, in seconds. By default, this value is 60.
|
||||||
VhostHttpTimeout int64 `json:"vhost_http_timeout"`
|
VhostHttpTimeout int64 `json:"vhost_http_timeout"`
|
||||||
|
|
||||||
|
// DashboardAddr specifies the address that the dashboard binds to. By
|
||||||
|
// default, this value is "0.0.0.0".
|
||||||
DashboardAddr string `json:"dashboard_addr"`
|
DashboardAddr string `json:"dashboard_addr"`
|
||||||
|
|
||||||
// if DashboardPort equals 0, dashboard is not available
|
// DashboardPort specifies the port that the dashboard listens on. If this
|
||||||
|
// value is 0, the dashboard will not be started. By default, this value is
|
||||||
|
// 0.
|
||||||
DashboardPort int `json:"dashboard_port"`
|
DashboardPort int `json:"dashboard_port"`
|
||||||
|
// DashboardUser specifies the username that the dashboard will use for
|
||||||
|
// login. By default, this value is "admin".
|
||||||
DashboardUser string `json:"dashboard_user"`
|
DashboardUser string `json:"dashboard_user"`
|
||||||
|
// DashboardUser specifies the password that the dashboard will use for
|
||||||
|
// login. By default, this value is "admin".
|
||||||
DashboardPwd string `json:"dashboard_pwd"`
|
DashboardPwd string `json:"dashboard_pwd"`
|
||||||
|
// AssetsDir specifies the local directory that the dashboard will load
|
||||||
|
// resources from. If this value is "", assets will be loaded from the
|
||||||
|
// bundled executable using statik. By default, this value is "".
|
||||||
AssetsDir string `json:"asserts_dir"`
|
AssetsDir string `json:"asserts_dir"`
|
||||||
|
// LogFile specifies a file where logs will be written to. This value will
|
||||||
|
// only be used if LogWay is set appropriately. By default, this value is
|
||||||
|
// "console".
|
||||||
LogFile string `json:"log_file"`
|
LogFile string `json:"log_file"`
|
||||||
LogWay string `json:"log_way"` // console or file
|
// LogWay specifies the way logging is managed. Valid values are "console"
|
||||||
|
// or "file". If "console" is used, logs will be printed to stdout. If
|
||||||
|
// "file" is used, logs will be printed to LogFile. By default, this value
|
||||||
|
// is "console".
|
||||||
|
LogWay string `json:"log_way"`
|
||||||
|
// LogLevel specifies the minimum log level. Valid values are "trace",
|
||||||
|
// "debug", "info", "warn", and "error". By default, this value is "info".
|
||||||
LogLevel string `json:"log_level"`
|
LogLevel string `json:"log_level"`
|
||||||
|
// LogMaxDays specifies the maximum number of days to store log information
|
||||||
|
// before deletion. This is only used if LogWay == "file". By default, this
|
||||||
|
// value is 0.
|
||||||
LogMaxDays int64 `json:"log_max_days"`
|
LogMaxDays int64 `json:"log_max_days"`
|
||||||
|
// DisableLogColor disables log colors when LogWay == "console" when set to
|
||||||
|
// true. By default, this value is false.
|
||||||
|
DisableLogColor bool `json:"disable_log_color"`
|
||||||
|
// Token specifies the authorization token used to authenticate keys
|
||||||
|
// received from clients. Clients must have a matching token to be
|
||||||
|
// authorized to use the server. By default, this value is "".
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
// SubDomainHost specifies the domain that will be attached to sub-domains
|
||||||
|
// requested by the client when using Vhost proxying. For example, if this
|
||||||
|
// value is set to "frps.com" and the client requested the subdomain
|
||||||
|
// "test", the resulting URL would be "test.frps.com". By default, this
|
||||||
|
// value is "".
|
||||||
SubDomainHost string `json:"subdomain_host"`
|
SubDomainHost string `json:"subdomain_host"`
|
||||||
|
// TcpMux toggles TCP stream multiplexing. This allows multiple requests
|
||||||
|
// from a client to share a single TCP connection. By default, this value
|
||||||
|
// is true.
|
||||||
TcpMux bool `json:"tcp_mux"`
|
TcpMux bool `json:"tcp_mux"`
|
||||||
|
// Custom404Page specifies a path to a custom 404 page to display. If this
|
||||||
|
// value is "", a default page will be displayed. By default, this value is
|
||||||
|
// "".
|
||||||
Custom404Page string `json:"custom_404_page"`
|
Custom404Page string `json:"custom_404_page"`
|
||||||
|
|
||||||
|
// AllowPorts specifies a set of ports that clients are able to proxy to.
|
||||||
|
// If the length of this value is 0, all ports are allowed. By default,
|
||||||
|
// this value is an empty set.
|
||||||
AllowPorts map[int]struct{}
|
AllowPorts map[int]struct{}
|
||||||
|
// MaxPoolCount specifies the maximum pool size for each proxy. By default,
|
||||||
|
// this value is 5.
|
||||||
MaxPoolCount int64 `json:"max_pool_count"`
|
MaxPoolCount int64 `json:"max_pool_count"`
|
||||||
|
// MaxPortsPerClient specifies the maximum number of ports a single client
|
||||||
|
// may proxy to. If this value is 0, no limit will be applied. By default,
|
||||||
|
// this value is 0.
|
||||||
MaxPortsPerClient int64 `json:"max_ports_per_client"`
|
MaxPortsPerClient int64 `json:"max_ports_per_client"`
|
||||||
|
// HeartBeatTimeout specifies the maximum time to wait for a heartbeat
|
||||||
|
// before terminating the connection. It is not recommended to change this
|
||||||
|
// value. By default, this value is 90.
|
||||||
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
|
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
|
||||||
|
// UserConnTimeout specifies the maximum time to wait for a work
|
||||||
|
// connection. By default, this value is 10.
|
||||||
UserConnTimeout int64 `json:"user_conn_timeout"`
|
UserConnTimeout int64 `json:"user_conn_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultServerConf() *ServerCommonConf {
|
// GetDefaultServerConf returns a server configuration with reasonable
|
||||||
return &ServerCommonConf{
|
// defaults.
|
||||||
|
func GetDefaultServerConf() ServerCommonConf {
|
||||||
|
return ServerCommonConf{
|
||||||
BindAddr: "0.0.0.0",
|
BindAddr: "0.0.0.0",
|
||||||
BindPort: 7000,
|
BindPort: 7000,
|
||||||
BindUdpPort: 0,
|
BindUdpPort: 0,
|
||||||
|
@ -97,6 +157,7 @@ func GetDefaultServerConf() *ServerCommonConf {
|
||||||
LogWay: "console",
|
LogWay: "console",
|
||||||
LogLevel: "info",
|
LogLevel: "info",
|
||||||
LogMaxDays: 3,
|
LogMaxDays: 3,
|
||||||
|
DisableLogColor: false,
|
||||||
Token: "",
|
Token: "",
|
||||||
SubDomainHost: "",
|
SubDomainHost: "",
|
||||||
TcpMux: true,
|
TcpMux: true,
|
||||||
|
@ -109,16 +170,15 @@ func GetDefaultServerConf() *ServerCommonConf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnmarshalServerConfFromIni(defaultCfg *ServerCommonConf, content string) (cfg *ServerCommonConf, err error) {
|
// UnmarshalServerConfFromIni parses the contents of a server configuration ini
|
||||||
cfg = defaultCfg
|
// file and returns the resulting server configuration.
|
||||||
if cfg == nil {
|
func UnmarshalServerConfFromIni(content string) (cfg ServerCommonConf, err error) {
|
||||||
cfg = GetDefaultServerConf()
|
cfg = GetDefaultServerConf()
|
||||||
}
|
|
||||||
|
|
||||||
conf, err := ini.Load(strings.NewReader(content))
|
conf, err := ini.Load(strings.NewReader(content))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("parse ini conf file error: %v", err)
|
err = fmt.Errorf("parse ini conf file error: %v", err)
|
||||||
return nil, err
|
return ServerCommonConf{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -244,6 +304,10 @@ func UnmarshalServerConfFromIni(defaultCfg *ServerCommonConf, content string) (c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tmpStr, ok = conf.Get("common", "disable_log_color"); ok && tmpStr == "true" {
|
||||||
|
cfg.DisableLogColor = true
|
||||||
|
}
|
||||||
|
|
||||||
cfg.Token, _ = conf.Get("common", "token")
|
cfg.Token, _ = conf.Get("common", "token")
|
||||||
|
|
||||||
if allowPortsStr, ok := conf.Get("common", "allow_ports"); ok {
|
if allowPortsStr, ok := conf.Get("common", "allow_ports"); ok {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
)
|
)
|
||||||
|
@ -35,6 +36,7 @@ type HTTPS2HTTPPlugin struct {
|
||||||
keyPath string
|
keyPath string
|
||||||
hostHeaderRewrite string
|
hostHeaderRewrite string
|
||||||
localAddr string
|
localAddr string
|
||||||
|
headers map[string]string
|
||||||
|
|
||||||
l *Listener
|
l *Listener
|
||||||
s *http.Server
|
s *http.Server
|
||||||
|
@ -45,6 +47,15 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
|
||||||
keyPath := params["plugin_key_path"]
|
keyPath := params["plugin_key_path"]
|
||||||
localAddr := params["plugin_local_addr"]
|
localAddr := params["plugin_local_addr"]
|
||||||
hostHeaderRewrite := params["plugin_host_header_rewrite"]
|
hostHeaderRewrite := params["plugin_host_header_rewrite"]
|
||||||
|
headers := make(map[string]string)
|
||||||
|
for k, v := range params {
|
||||||
|
if !strings.HasPrefix(k, "plugin_header_") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if k = strings.TrimPrefix(k, "plugin_header_"); k != "" {
|
||||||
|
headers[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if crtPath == "" {
|
if crtPath == "" {
|
||||||
return nil, fmt.Errorf("plugin_crt_path is required")
|
return nil, fmt.Errorf("plugin_crt_path is required")
|
||||||
|
@ -63,6 +74,7 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
|
||||||
keyPath: keyPath,
|
keyPath: keyPath,
|
||||||
localAddr: localAddr,
|
localAddr: localAddr,
|
||||||
hostHeaderRewrite: hostHeaderRewrite,
|
hostHeaderRewrite: hostHeaderRewrite,
|
||||||
|
headers: headers,
|
||||||
l: listener,
|
l: listener,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +85,9 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
|
||||||
if p.hostHeaderRewrite != "" {
|
if p.hostHeaderRewrite != "" {
|
||||||
req.Host = p.hostHeaderRewrite
|
req.Host = p.hostHeaderRewrite
|
||||||
}
|
}
|
||||||
|
for k, v := range p.headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/consts"
|
"github.com/fatedier/frp/models/consts"
|
||||||
frpErr "github.com/fatedier/frp/models/errors"
|
frpErr "github.com/fatedier/frp/models/errors"
|
||||||
|
@ -129,11 +128,19 @@ type Control struct {
|
||||||
allShutdown *shutdown.Shutdown
|
allShutdown *shutdown.Shutdown
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
// Server configuration information
|
||||||
|
serverCfg config.ServerCommonConf
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManager,
|
func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManager,
|
||||||
statsCollector stats.Collector, ctlConn net.Conn, loginMsg *msg.Login) *Control {
|
statsCollector stats.Collector, ctlConn net.Conn, loginMsg *msg.Login,
|
||||||
|
serverCfg config.ServerCommonConf) *Control {
|
||||||
|
|
||||||
|
poolCount := loginMsg.PoolCount
|
||||||
|
if poolCount > int(serverCfg.MaxPoolCount) {
|
||||||
|
poolCount = int(serverCfg.MaxPoolCount)
|
||||||
|
}
|
||||||
return &Control{
|
return &Control{
|
||||||
rc: rc,
|
rc: rc,
|
||||||
pxyManager: pxyManager,
|
pxyManager: pxyManager,
|
||||||
|
@ -142,9 +149,9 @@ func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManage
|
||||||
loginMsg: loginMsg,
|
loginMsg: loginMsg,
|
||||||
sendCh: make(chan msg.Message, 10),
|
sendCh: make(chan msg.Message, 10),
|
||||||
readCh: make(chan msg.Message, 10),
|
readCh: make(chan msg.Message, 10),
|
||||||
workConnCh: make(chan net.Conn, loginMsg.PoolCount+10),
|
workConnCh: make(chan net.Conn, poolCount+10),
|
||||||
proxies: make(map[string]proxy.Proxy),
|
proxies: make(map[string]proxy.Proxy),
|
||||||
poolCount: loginMsg.PoolCount,
|
poolCount: poolCount,
|
||||||
portsUsedNum: 0,
|
portsUsedNum: 0,
|
||||||
lastPing: time.Now(),
|
lastPing: time.Now(),
|
||||||
runId: loginMsg.RunId,
|
runId: loginMsg.RunId,
|
||||||
|
@ -153,6 +160,7 @@ func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManage
|
||||||
writerShutdown: shutdown.New(),
|
writerShutdown: shutdown.New(),
|
||||||
managerShutdown: shutdown.New(),
|
managerShutdown: shutdown.New(),
|
||||||
allShutdown: shutdown.New(),
|
allShutdown: shutdown.New(),
|
||||||
|
serverCfg: serverCfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +169,7 @@ func (ctl *Control) Start() {
|
||||||
loginRespMsg := &msg.LoginResp{
|
loginRespMsg := &msg.LoginResp{
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
RunId: ctl.runId,
|
RunId: ctl.runId,
|
||||||
ServerUdpPort: g.GlbServerCfg.BindUdpPort,
|
ServerUdpPort: ctl.serverCfg.BindUdpPort,
|
||||||
Error: "",
|
Error: "",
|
||||||
}
|
}
|
||||||
msg.WriteMsg(ctl.conn, loginRespMsg)
|
msg.WriteMsg(ctl.conn, loginRespMsg)
|
||||||
|
@ -232,7 +240,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-time.After(time.Duration(g.GlbServerCfg.UserConnTimeout) * time.Second):
|
case <-time.After(time.Duration(ctl.serverCfg.UserConnTimeout) * time.Second):
|
||||||
err = fmt.Errorf("timeout trying to get work connection")
|
err = fmt.Errorf("timeout trying to get work connection")
|
||||||
ctl.conn.Warn("%v", err)
|
ctl.conn.Warn("%v", err)
|
||||||
return
|
return
|
||||||
|
@ -263,7 +271,7 @@ func (ctl *Control) writer() {
|
||||||
defer ctl.allShutdown.Start()
|
defer ctl.allShutdown.Start()
|
||||||
defer ctl.writerShutdown.Done()
|
defer ctl.writerShutdown.Done()
|
||||||
|
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(g.GlbServerCfg.Token))
|
encWriter, err := crypto.NewWriter(ctl.conn, []byte(ctl.serverCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.conn.Error("crypto new writer error: %v", err)
|
ctl.conn.Error("crypto new writer error: %v", err)
|
||||||
ctl.allShutdown.Start()
|
ctl.allShutdown.Start()
|
||||||
|
@ -293,7 +301,7 @@ func (ctl *Control) reader() {
|
||||||
defer ctl.allShutdown.Start()
|
defer ctl.allShutdown.Start()
|
||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
|
|
||||||
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbServerCfg.Token))
|
encReader := crypto.NewReader(ctl.conn, []byte(ctl.serverCfg.Token))
|
||||||
for {
|
for {
|
||||||
if m, err := msg.ReadMsg(encReader); err != nil {
|
if m, err := msg.ReadMsg(encReader); err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
|
@ -374,7 +382,7 @@ func (ctl *Control) manager() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-heartbeat.C:
|
case <-heartbeat.C:
|
||||||
if time.Since(ctl.lastPing) > time.Duration(g.GlbServerCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.conn.Warn("heartbeat timeout")
|
ctl.conn.Warn("heartbeat timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -417,22 +425,22 @@ func (ctl *Control) manager() {
|
||||||
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
|
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
|
||||||
var pxyConf config.ProxyConf
|
var pxyConf config.ProxyConf
|
||||||
// Load configures from NewProxy message and check.
|
// Load configures from NewProxy message and check.
|
||||||
pxyConf, err = config.NewProxyConfFromMsg(pxyMsg)
|
pxyConf, err = config.NewProxyConfFromMsg(pxyMsg, ctl.serverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProxy will return a interface Proxy.
|
// NewProxy will return a interface Proxy.
|
||||||
// In fact it create different proxies by different proxy type, we just call run() here.
|
// In fact it create different proxies by different proxy type, we just call run() here.
|
||||||
pxy, err := proxy.NewProxy(ctl.runId, ctl.rc, ctl.statsCollector, ctl.poolCount, ctl.GetWorkConn, pxyConf)
|
pxy, err := proxy.NewProxy(ctl.runId, ctl.rc, ctl.statsCollector, ctl.poolCount, ctl.GetWorkConn, pxyConf, ctl.serverCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return remoteAddr, err
|
return remoteAddr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check ports used number in each client
|
// Check ports used number in each client
|
||||||
if g.GlbServerCfg.MaxPortsPerClient > 0 {
|
if ctl.serverCfg.MaxPortsPerClient > 0 {
|
||||||
ctl.mu.Lock()
|
ctl.mu.Lock()
|
||||||
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(g.GlbServerCfg.MaxPortsPerClient) {
|
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(ctl.serverCfg.MaxPortsPerClient) {
|
||||||
ctl.mu.Unlock()
|
ctl.mu.Unlock()
|
||||||
err = fmt.Errorf("exceed the max_ports_per_client")
|
err = fmt.Errorf("exceed the max_ports_per_client")
|
||||||
return
|
return
|
||||||
|
@ -478,7 +486,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.GlbServerCfg.MaxPortsPerClient > 0 {
|
if ctl.serverCfg.MaxPortsPerClient > 0 {
|
||||||
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
|
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
|
||||||
}
|
}
|
||||||
pxy.Close()
|
pxy.Close()
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -36,7 +35,7 @@ func (svr *Service) RunDashboardServer(addr string, port int) (err error) {
|
||||||
// url router
|
// url router
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
user, passwd := g.GlbServerCfg.DashboardUser, g.GlbServerCfg.DashboardPwd
|
user, passwd := svr.cfg.DashboardUser, svr.cfg.DashboardPwd
|
||||||
router.Use(frpNet.NewHttpAuthMiddleware(user, passwd).Middleware)
|
router.Use(frpNet.NewHttpAuthMiddleware(user, passwd).Middleware)
|
||||||
|
|
||||||
// api, see dashboard_api.go
|
// api, see dashboard_api.go
|
||||||
|
|
|
@ -18,7 +18,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/consts"
|
"github.com/fatedier/frp/models/consts"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
@ -63,19 +62,18 @@ func (svr *Service) ApiServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
log.Info("Http request: [%s]", r.URL.Path)
|
log.Info("Http request: [%s]", r.URL.Path)
|
||||||
cfg := &g.GlbServerCfg.ServerCommonConf
|
|
||||||
serverStats := svr.statsCollector.GetServer()
|
serverStats := svr.statsCollector.GetServer()
|
||||||
svrResp := ServerInfoResp{
|
svrResp := ServerInfoResp{
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
BindPort: cfg.BindPort,
|
BindPort: svr.cfg.BindPort,
|
||||||
BindUdpPort: cfg.BindUdpPort,
|
BindUdpPort: svr.cfg.BindUdpPort,
|
||||||
VhostHttpPort: cfg.VhostHttpPort,
|
VhostHttpPort: svr.cfg.VhostHttpPort,
|
||||||
VhostHttpsPort: cfg.VhostHttpsPort,
|
VhostHttpsPort: svr.cfg.VhostHttpsPort,
|
||||||
KcpBindPort: cfg.KcpBindPort,
|
KcpBindPort: svr.cfg.KcpBindPort,
|
||||||
SubdomainHost: cfg.SubDomainHost,
|
SubdomainHost: svr.cfg.SubDomainHost,
|
||||||
MaxPoolCount: cfg.MaxPoolCount,
|
MaxPoolCount: svr.cfg.MaxPoolCount,
|
||||||
MaxPortsPerClient: cfg.MaxPortsPerClient,
|
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
|
||||||
HeartBeatTimeout: cfg.HeartBeatTimeout,
|
HeartBeatTimeout: svr.cfg.HeartBeatTimeout,
|
||||||
|
|
||||||
TotalTrafficIn: serverStats.TotalTrafficIn,
|
TotalTrafficIn: serverStats.TotalTrafficIn,
|
||||||
TotalTrafficOut: serverStats.TotalTrafficOut,
|
TotalTrafficOut: serverStats.TotalTrafficOut,
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/server/stats"
|
"github.com/fatedier/frp/server/stats"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
@ -88,13 +87,13 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
||||||
pxy.rc.HttpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
pxy.rc.HttpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(g.GlbServerCfg.VhostHttpPort)))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(pxy.serverCfg.VhostHttpPort)))
|
||||||
pxy.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
pxy.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
||||||
for _, location := range locations {
|
for _, location := range locations {
|
||||||
routeConfig.Location = location
|
routeConfig.Location = location
|
||||||
tmpDomain := routeConfig.Domain
|
tmpDomain := routeConfig.Domain
|
||||||
|
@ -119,7 +118,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
||||||
pxy.rc.HttpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
pxy.rc.HttpReverseProxy.UnRegister(tmpDomain, tmpLocation)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
addrs = append(addrs, util.CanonicalAddr(tmpDomain, g.GlbServerCfg.VhostHttpPort))
|
addrs = append(addrs, util.CanonicalAddr(tmpDomain, pxy.serverCfg.VhostHttpPort))
|
||||||
|
|
||||||
pxy.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
pxy.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +146,7 @@ func (pxy *HttpProxy) GetRealConn(remoteAddr string) (workConn frpNet.Conn, err
|
||||||
|
|
||||||
var rwc io.ReadWriteCloser = tmpConn
|
var rwc io.ReadWriteCloser = tmpConn
|
||||||
if pxy.cfg.UseEncryption {
|
if pxy.cfg.UseEncryption {
|
||||||
rwc, err = frpIo.WithEncryption(rwc, []byte(g.GlbServerCfg.Token))
|
rwc, err = frpIo.WithEncryption(rwc, []byte(pxy.serverCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
pxy.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,7 +17,6 @@ package proxy
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
"github.com/fatedier/frp/utils/vhost"
|
"github.com/fatedier/frp/utils/vhost"
|
||||||
|
@ -51,11 +50,11 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
||||||
l.AddLogPrefix(pxy.name)
|
l.AddLogPrefix(pxy.name)
|
||||||
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
pxy.listeners = append(pxy.listeners, l)
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, g.GlbServerCfg.VhostHttpsPort))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHttpsPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
||||||
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(routeConfig)
|
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(routeConfig)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
|
@ -64,7 +63,7 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
||||||
l.AddLogPrefix(pxy.name)
|
l.AddLogPrefix(pxy.name)
|
||||||
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
|
||||||
pxy.listeners = append(pxy.listeners, l)
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(g.GlbServerCfg.VhostHttpsPort)))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(pxy.serverCfg.VhostHttpsPort)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/server/controller"
|
"github.com/fatedier/frp/server/controller"
|
||||||
|
@ -52,6 +51,7 @@ type BaseProxy struct {
|
||||||
usedPortsNum int
|
usedPortsNum int
|
||||||
poolCount int
|
poolCount int
|
||||||
getWorkConnFn GetWorkConnFn
|
getWorkConnFn GetWorkConnFn
|
||||||
|
serverCfg config.ServerCommonConf
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
log.Logger
|
log.Logger
|
||||||
|
@ -126,7 +126,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn frpNet.Co
|
||||||
// startListenHandler start a goroutine handler for each listener.
|
// startListenHandler start a goroutine handler for each listener.
|
||||||
// p: p will just be passed to handler(Proxy, frpNet.Conn).
|
// p: p will just be passed to handler(Proxy, frpNet.Conn).
|
||||||
// handler: each proxy type can set different handler function to deal with connections accepted from listeners.
|
// handler: each proxy type can set different handler function to deal with connections accepted from listeners.
|
||||||
func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, frpNet.Conn, stats.Collector)) {
|
func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, frpNet.Conn, stats.Collector, config.ServerCommonConf)) {
|
||||||
for _, listener := range pxy.listeners {
|
for _, listener := range pxy.listeners {
|
||||||
go func(l frpNet.Listener) {
|
go func(l frpNet.Listener) {
|
||||||
for {
|
for {
|
||||||
|
@ -138,14 +138,14 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, frpNet.Con
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pxy.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
pxy.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
||||||
go handler(p, c, pxy.statsCollector)
|
go handler(p, c, pxy.statsCollector, pxy.serverCfg)
|
||||||
}
|
}
|
||||||
}(listener)
|
}(listener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(runId string, rc *controller.ResourceController, statsCollector stats.Collector, poolCount int,
|
func NewProxy(runId string, rc *controller.ResourceController, statsCollector stats.Collector, poolCount int,
|
||||||
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf) (pxy Proxy, err error) {
|
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf) (pxy Proxy, err error) {
|
||||||
|
|
||||||
basePxy := BaseProxy{
|
basePxy := BaseProxy{
|
||||||
name: pxyConf.GetBaseInfo().ProxyName,
|
name: pxyConf.GetBaseInfo().ProxyName,
|
||||||
|
@ -155,6 +155,7 @@ func NewProxy(runId string, rc *controller.ResourceController, statsCollector st
|
||||||
poolCount: poolCount,
|
poolCount: poolCount,
|
||||||
getWorkConnFn: getWorkConnFn,
|
getWorkConnFn: getWorkConnFn,
|
||||||
Logger: log.NewPrefixLogger(runId),
|
Logger: log.NewPrefixLogger(runId),
|
||||||
|
serverCfg: serverCfg,
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.TcpProxyConf:
|
case *config.TcpProxyConf:
|
||||||
|
@ -198,7 +199,7 @@ func NewProxy(runId string, rc *controller.ResourceController, statsCollector st
|
||||||
|
|
||||||
// HandleUserTcpConnection is used for incoming tcp user connections.
|
// HandleUserTcpConnection is used for incoming tcp user connections.
|
||||||
// It can be used for tcp, http, https type.
|
// It can be used for tcp, http, https type.
|
||||||
func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn, statsCollector stats.Collector) {
|
func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn, statsCollector stats.Collector, serverCfg config.ServerCommonConf) {
|
||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
// try all connections from the pool
|
// try all connections from the pool
|
||||||
|
@ -211,7 +212,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn, statsCollector sta
|
||||||
var local io.ReadWriteCloser = workConn
|
var local io.ReadWriteCloser = workConn
|
||||||
cfg := pxy.GetConf().GetBaseInfo()
|
cfg := pxy.GetConf().GetBaseInfo()
|
||||||
if cfg.UseEncryption {
|
if cfg.UseEncryption {
|
||||||
local, err = frpIo.WithEncryption(local, []byte(g.GlbServerCfg.Token))
|
local, err = frpIo.WithEncryption(local, []byte(serverCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
pxy.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,7 +17,6 @@ package proxy
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
)
|
)
|
||||||
|
@ -31,7 +30,7 @@ type TcpProxy struct {
|
||||||
|
|
||||||
func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
||||||
if pxy.cfg.Group != "" {
|
if pxy.cfg.Group != "" {
|
||||||
l, realPort, errRet := pxy.rc.TcpGroupCtl.Listen(pxy.name, pxy.cfg.Group, pxy.cfg.GroupKey, g.GlbServerCfg.ProxyBindAddr, pxy.cfg.RemotePort)
|
l, realPort, errRet := pxy.rc.TcpGroupCtl.Listen(pxy.name, pxy.cfg.Group, pxy.cfg.GroupKey, pxy.serverCfg.ProxyBindAddr, pxy.cfg.RemotePort)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
|
@ -56,7 +55,7 @@ func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
||||||
pxy.rc.TcpPortManager.Release(pxy.realPort)
|
pxy.rc.TcpPortManager.Release(pxy.realPort)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
listener, errRet := frpNet.ListenTcp(g.GlbServerCfg.ProxyBindAddr, pxy.realPort)
|
listener, errRet := frpNet.ListenTcp(pxy.serverCfg.ProxyBindAddr, pxy.realPort)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/g"
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/proto/udp"
|
"github.com/fatedier/frp/models/proto/udp"
|
||||||
|
@ -67,7 +66,7 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
|
||||||
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
remoteAddr = fmt.Sprintf(":%d", pxy.realPort)
|
||||||
pxy.cfg.RemotePort = pxy.realPort
|
pxy.cfg.RemotePort = pxy.realPort
|
||||||
addr, errRet := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", g.GlbServerCfg.ProxyBindAddr, pxy.realPort))
|
addr, errRet := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", pxy.serverCfg.ProxyBindAddr, pxy.realPort))
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/assets"
|
"github.com/fatedier/frp/assets"
|
||||||
"github.com/fatedier/frp/g"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/nathole"
|
"github.com/fatedier/frp/models/nathole"
|
||||||
"github.com/fatedier/frp/server/controller"
|
"github.com/fatedier/frp/server/controller"
|
||||||
|
@ -51,8 +51,6 @@ const (
|
||||||
connReadTimeout time.Duration = 10 * time.Second
|
connReadTimeout time.Duration = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
var ServerService *Service
|
|
||||||
|
|
||||||
// Server service
|
// Server service
|
||||||
type Service struct {
|
type Service struct {
|
||||||
// Dispatch connections to different handlers listen on same port
|
// Dispatch connections to different handlers listen on same port
|
||||||
|
@ -86,10 +84,11 @@ type Service struct {
|
||||||
statsCollector stats.Collector
|
statsCollector stats.Collector
|
||||||
|
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tls.Config
|
||||||
|
|
||||||
|
cfg config.ServerCommonConf
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService() (svr *Service, err error) {
|
func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
|
||||||
cfg := &g.GlbServerCfg.ServerCommonConf
|
|
||||||
svr = &Service{
|
svr = &Service{
|
||||||
ctlManager: NewControlManager(),
|
ctlManager: NewControlManager(),
|
||||||
pxyManager: proxy.NewProxyManager(),
|
pxyManager: proxy.NewProxyManager(),
|
||||||
|
@ -100,6 +99,7 @@ func NewService() (svr *Service, err error) {
|
||||||
},
|
},
|
||||||
httpVhostRouter: vhost.NewVhostRouters(),
|
httpVhostRouter: vhost.NewVhostRouters(),
|
||||||
tlsConfig: generateTLSConfig(),
|
tlsConfig: generateTLSConfig(),
|
||||||
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init group controller
|
// Init group controller
|
||||||
|
@ -108,13 +108,6 @@ func NewService() (svr *Service, err error) {
|
||||||
// Init HTTP group controller
|
// Init HTTP group controller
|
||||||
svr.rc.HTTPGroupCtl = group.NewHTTPGroupController(svr.httpVhostRouter)
|
svr.rc.HTTPGroupCtl = group.NewHTTPGroupController(svr.httpVhostRouter)
|
||||||
|
|
||||||
// Init assets
|
|
||||||
err = assets.Load(cfg.AssetsDir)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("Load assets error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init 404 not found page
|
// Init 404 not found page
|
||||||
vhost.NotFoundPagePath = cfg.Custom404Page
|
vhost.NotFoundPagePath = cfg.Custom404Page
|
||||||
|
|
||||||
|
@ -231,6 +224,13 @@ func NewService() (svr *Service, err error) {
|
||||||
var statsEnable bool
|
var statsEnable bool
|
||||||
// Create dashboard web server.
|
// Create dashboard web server.
|
||||||
if cfg.DashboardPort > 0 {
|
if cfg.DashboardPort > 0 {
|
||||||
|
// Init dashboard assets
|
||||||
|
err = assets.Load(cfg.AssetsDir)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Load assets error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = svr.RunDashboardServer(cfg.DashboardAddr, cfg.DashboardPort)
|
err = svr.RunDashboardServer(cfg.DashboardAddr, cfg.DashboardPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Create dashboard web server error, %v", err)
|
err = fmt.Errorf("Create dashboard web server error, %v", err)
|
||||||
|
@ -248,7 +248,7 @@ func (svr *Service) Run() {
|
||||||
if svr.rc.NatHoleController != nil {
|
if svr.rc.NatHoleController != nil {
|
||||||
go svr.rc.NatHoleController.Run()
|
go svr.rc.NatHoleController.Run()
|
||||||
}
|
}
|
||||||
if g.GlbServerCfg.KcpBindPort > 0 {
|
if svr.cfg.KcpBindPort > 0 {
|
||||||
go svr.HandleListener(svr.kcpListener)
|
go svr.HandleListener(svr.kcpListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.GlbServerCfg.TcpMux {
|
if svr.cfg.TcpMux {
|
||||||
fmuxCfg := fmux.DefaultConfig()
|
fmuxCfg := fmux.DefaultConfig()
|
||||||
fmuxCfg.KeepAliveInterval = 20 * time.Second
|
fmuxCfg.KeepAliveInterval = 20 * time.Second
|
||||||
fmuxCfg.LogOutput = ioutil.Discard
|
fmuxCfg.LogOutput = ioutil.Discard
|
||||||
|
@ -363,7 +363,7 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check auth.
|
// Check auth.
|
||||||
if util.GetAuthKey(g.GlbServerCfg.Token, loginMsg.Timestamp) != loginMsg.PrivilegeKey {
|
if util.GetAuthKey(svr.cfg.Token, loginMsg.Timestamp) != loginMsg.PrivilegeKey {
|
||||||
err = fmt.Errorf("authorization failed")
|
err = fmt.Errorf("authorization failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctl := NewControl(svr.rc, svr.pxyManager, svr.statsCollector, ctlConn, loginMsg)
|
ctl := NewControl(svr.rc, svr.pxyManager, svr.statsCollector, ctlConn, loginMsg, svr.cfg)
|
||||||
|
|
||||||
if oldCtl := svr.ctlManager.Add(loginMsg.RunId, ctl); oldCtl != nil {
|
if oldCtl := svr.ctlManager.Add(loginMsg.RunId, ctl); oldCtl != nil {
|
||||||
oldCtl.allShutdown.WaitDone()
|
oldCtl.allShutdown.WaitDone()
|
||||||
|
|
|
@ -67,6 +67,20 @@ custom_domains = test2.com
|
||||||
health_check_type = http
|
health_check_type = http
|
||||||
health_check_interval_s = 1
|
health_check_interval_s = 1
|
||||||
health_check_url = /health
|
health_check_url = /health
|
||||||
|
|
||||||
|
[http3]
|
||||||
|
type = http
|
||||||
|
local_port = 15005
|
||||||
|
custom_domains = test.balancing.com
|
||||||
|
group = test-balancing
|
||||||
|
group_key = 123
|
||||||
|
|
||||||
|
[http4]
|
||||||
|
type = http
|
||||||
|
local_port = 15006
|
||||||
|
custom_domains = test.balancing.com
|
||||||
|
group = test-balancing
|
||||||
|
group_key = 123
|
||||||
`
|
`
|
||||||
|
|
||||||
func TestHealthCheck(t *testing.T) {
|
func TestHealthCheck(t *testing.T) {
|
||||||
|
@ -124,6 +138,22 @@ func TestHealthCheck(t *testing.T) {
|
||||||
defer httpSvc2.Stop()
|
defer httpSvc2.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
httpSvc3 := mock.NewHttpServer(15005, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("http3"))
|
||||||
|
})
|
||||||
|
err = httpSvc3.Start()
|
||||||
|
if assert.NoError(err) {
|
||||||
|
defer httpSvc3.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
httpSvc4 := mock.NewHttpServer(15006, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("http4"))
|
||||||
|
})
|
||||||
|
err = httpSvc4.Start()
|
||||||
|
if assert.NoError(err) {
|
||||||
|
defer httpSvc4.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
|
||||||
// ****** start frps and frpc ******
|
// ****** start frps and frpc ******
|
||||||
|
@ -244,4 +274,20 @@ func TestHealthCheck(t *testing.T) {
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(200, code)
|
assert.Equal(200, code)
|
||||||
assert.Equal("http2", body)
|
assert.Equal("http2", body)
|
||||||
|
|
||||||
|
// ****** load balancing type http ******
|
||||||
|
result = make([]string, 0)
|
||||||
|
|
||||||
|
code, body, _, err = util.SendHttpMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(200, code)
|
||||||
|
result = append(result, body)
|
||||||
|
|
||||||
|
code, body, _, err = util.SendHttpMsg("GET", "http://127.0.0.1:14000/xxx", "test.balancing.com", nil, "")
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(200, code)
|
||||||
|
result = append(result, body)
|
||||||
|
|
||||||
|
assert.Contains(result, "http3")
|
||||||
|
assert.Contains(result, "http4")
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,20 @@ func init() {
|
||||||
Log.SetLogFuncCallDepth(Log.GetLogFuncCallDepth() + 1)
|
Log.SetLogFuncCallDepth(Log.GetLogFuncCallDepth() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitLog(logWay string, logFile string, logLevel string, maxdays int64) {
|
func InitLog(logWay string, logFile string, logLevel string, maxdays int64, disableLogColor bool) {
|
||||||
SetLogFile(logWay, logFile, maxdays)
|
SetLogFile(logWay, logFile, maxdays, disableLogColor)
|
||||||
SetLogLevel(logLevel)
|
SetLogLevel(logLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogFile to configure log params
|
// SetLogFile to configure log params
|
||||||
// logWay: file or console
|
// logWay: file or console
|
||||||
func SetLogFile(logWay string, logFile string, maxdays int64) {
|
func SetLogFile(logWay string, logFile string, maxdays int64, disableLogColor bool) {
|
||||||
if logWay == "console" {
|
if logWay == "console" {
|
||||||
Log.SetLogger("console", "")
|
params := ""
|
||||||
|
if disableLogColor {
|
||||||
|
params = fmt.Sprintf(`{"color": false}`)
|
||||||
|
}
|
||||||
|
Log.SetLogger("console", params)
|
||||||
} else {
|
} else {
|
||||||
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays)
|
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays)
|
||||||
Log.SetLogger("file", params)
|
Log.SetLogger("file", params)
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version string = "0.28.2"
|
var version string = "0.29.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
|
Loading…
Reference in New Issue