Merge pull request #1415 from fatedier/dev

bump version to v0.29.0
pull/1481/head v0.29.0
fatedier 2019-08-29 21:22:30 +08:00 committed by GitHub
commit e62d9a5242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 676 additions and 403 deletions

View File

@ -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.
**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
@ -265,6 +265,7 @@ Configure frps same as above.
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
```
2. Visit `https://test.yourdomain.com`.

View File

@ -129,7 +129,7 @@ master 分支用于发布稳定版本dev 分支用于开发,您可以尝试
vhost_http_port = 8080
```
2. 启动 frps
2. 启动 frps
`./frps -c ./frps.ini`
@ -270,6 +270,7 @@ frps 的部署步骤同上。
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
```
2. 通过浏览器访问 `https://test.yourdomain.com` 即可。

View File

@ -21,7 +21,6 @@ import (
"time"
"github.com/fatedier/frp/assets"
"github.com/fatedier/frp/g"
frpNet "github.com/fatedier/frp/utils/net"
"github.com/gorilla/mux"
@ -36,7 +35,7 @@ func (svr *Service) RunAdminServer(addr string, port int) (err error) {
// url router
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)
// api, see dashboard_api.go

View File

@ -23,7 +23,6 @@ import (
"strings"
"github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"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 {
res.Code = 400
res.Msg = err.Error()
@ -55,7 +54,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
return
}
newCommonCfg, err := config.UnmarshalClientConfFromIni(nil, content)
newCommonCfg, err := config.UnmarshalClientConfFromIni(content)
if err != nil {
res.Code = 400
res.Msg = err.Error()
@ -63,7 +62,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
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 {
res.Code = 400
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) 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{
Name: status.Name,
Type: status.Type,
@ -121,18 +120,18 @@ func NewProxyStatusResp(status *proxy.ProxyStatus) ProxyStatusResp {
}
psr.Plugin = cfg.Plugin
if status.Err != "" {
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
} else {
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
psr.RemoteAddr = serverAddr + status.RemoteAddr
}
case *config.UdpProxyConf:
if cfg.LocalPort != 0 {
psr.LocalAddr = fmt.Sprintf("%s:%d", cfg.LocalIp, cfg.LocalPort)
}
if status.Err != "" {
psr.RemoteAddr = fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, cfg.RemotePort)
psr.RemoteAddr = fmt.Sprintf("%s:%d", serverAddr, cfg.RemotePort)
} else {
psr.RemoteAddr = g.GlbClientCfg.ServerAddr + status.RemoteAddr
psr.RemoteAddr = serverAddr + status.RemoteAddr
}
case *config.HttpProxyConf:
if cfg.LocalPort != 0 {
@ -184,17 +183,17 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
for _, status := range ps {
switch status.Type {
case "tcp":
res.Tcp = append(res.Tcp, NewProxyStatusResp(status))
res.Tcp = append(res.Tcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "udp":
res.Udp = append(res.Udp, NewProxyStatusResp(status))
res.Udp = append(res.Udp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "http":
res.Http = append(res.Http, NewProxyStatusResp(status))
res.Http = append(res.Http, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "https":
res.Https = append(res.Https, NewProxyStatusResp(status))
res.Https = append(res.Https, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "stcp":
res.Stcp = append(res.Stcp, NewProxyStatusResp(status))
res.Stcp = append(res.Stcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
case "xtcp":
res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status))
res.Xtcp = append(res.Xtcp, NewProxyStatusResp(status, svr.cfg.ServerAddr))
}
}
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.Msg = "frpc has no config file path"
log.Warn("%s", res.Msg)
return
}
content, err := config.GetRenderedConfFromFile(g.GlbClientCfg.CfgFile)
content, err := config.GetRenderedConfFromFile(svr.cfgFile)
if err != nil {
res.Code = 400
res.Msg = err.Error()
@ -277,7 +276,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
// get token from origin content
token := ""
b, err := ioutil.ReadFile(g.GlbClientCfg.CfgFile)
b, err := ioutil.ReadFile(svr.cfgFile)
if err != nil {
res.Code = 400
res.Msg = err.Error()
@ -316,7 +315,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
}
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 {
res.Code = 500
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)

View File

@ -23,7 +23,6 @@ import (
"time"
"github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/utils/log"
@ -65,16 +64,24 @@ type Control struct {
// last time got the Pong message
lastPong time.Time
// The client configuration
clientCfg config.ClientCommonConf
readerShutdown *shutdown.Shutdown
writerShutdown *shutdown.Shutdown
msgHandlerShutdown *shutdown.Shutdown
// The UDP port that the server is listening on
serverUDPPort int
mu sync.RWMutex
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{
runId: runId,
conn: conn,
@ -84,12 +91,14 @@ func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, pxyCfgs m
readCh: make(chan msg.Message, 100),
closedCh: make(chan struct{}),
closedDoneCh: make(chan struct{}),
clientCfg: clientCfg,
readerShutdown: shutdown.New(),
writerShutdown: shutdown.New(),
msgHandlerShutdown: shutdown.New(),
serverUDPPort: serverUDPPort,
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.Reload(visitorCfgs)
@ -161,7 +170,7 @@ func (ctl *Control) ClosedDoneCh() <-chan struct{} {
// connectServer return a new connection to frps
func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
if g.GlbClientCfg.TcpMux {
if ctl.clientCfg.TcpMux {
stream, errRet := ctl.session.OpenStream()
if errRet != nil {
err = errRet
@ -171,13 +180,13 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
conn = frpNet.WrapConn(stream)
} else {
var tlsConfig *tls.Config
if g.GlbClientCfg.TLSEnable {
if ctl.clientCfg.TLSEnable {
tlsConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HttpProxy, ctl.clientCfg.Protocol,
fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.ServerPort), tlsConfig)
if err != nil {
ctl.Warn("start new connection to server error: %v", err)
return
@ -197,7 +206,7 @@ func (ctl *Control) reader() {
defer ctl.readerShutdown.Done()
defer close(ctl.closedCh)
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbClientCfg.Token))
encReader := crypto.NewReader(ctl.conn, []byte(ctl.clientCfg.Token))
for {
if m, err := msg.ReadMsg(encReader); err != nil {
if err == io.EOF {
@ -217,7 +226,7 @@ func (ctl *Control) reader() {
// writer writes messages got from sendCh to frps
func (ctl *Control) writer() {
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 {
ctl.conn.Error("crypto new writer error: %v", err)
ctl.conn.Close()
@ -246,7 +255,7 @@ func (ctl *Control) msgHandler() {
}()
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()
hbCheck := time.NewTicker(time.Second)
defer hbCheck.Stop()
@ -260,7 +269,7 @@ func (ctl *Control) msgHandler() {
ctl.Debug("send heartbeat to server")
ctl.sendCh <- &msg.Ping{}
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")
// let reader() stop
ctl.conn.Close()

View File

@ -25,7 +25,6 @@ import (
"sync"
"time"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/models/plugin"
@ -51,9 +50,11 @@ type Proxy interface {
log.Logger
}
func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
func NewProxy(pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
baseProxy := BaseProxy{
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
clientCfg: clientCfg,
serverUDPPort: serverUDPPort,
}
switch cfg := pxyConf.(type) {
case *config.TcpProxyConf:
@ -91,8 +92,10 @@ func NewProxy(pxyConf config.ProxyConf) (pxy Proxy) {
}
type BaseProxy struct {
closed bool
mu sync.RWMutex
closed bool
mu sync.RWMutex
clientCfg config.ClientCommonConf
serverUDPPort int
log.Logger
}
@ -122,7 +125,7 @@ func (pxy *TcpProxy) Close() {
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token), m)
[]byte(pxy.clientCfg.Token), m)
}
// HTTP
@ -151,7 +154,7 @@ func (pxy *HttpProxy) Close() {
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token), m)
[]byte(pxy.clientCfg.Token), m)
}
// HTTPS
@ -180,7 +183,7 @@ func (pxy *HttpsProxy) Close() {
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token), m)
[]byte(pxy.clientCfg.Token), m)
}
// STCP
@ -209,7 +212,7 @@ func (pxy *StcpProxy) Close() {
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
[]byte(g.GlbClientCfg.Token), m)
[]byte(pxy.clientCfg.Token), m)
}
// XTCP
@ -250,7 +253,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
Sid: natHoleSidMsg.Sid,
}
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)
defer clientConn.Close()
@ -518,7 +521,7 @@ func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.
DestinationPort: m.DstPort,
}
if h.SourceAddress.To16() == nil {
if strings.Contains(m.SrcAddr, ".") {
h.TransportProtocol = pp.TCPv4
} else {
h.TransportProtocol = pp.TCPv6

View File

@ -20,17 +20,24 @@ type ProxyManager struct {
closed bool
mu sync.RWMutex
clientCfg config.ClientCommonConf
// The UDP port that the server is listening on
serverUDPPort int
logPrefix string
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{
proxies: make(map[string]*ProxyWrapper),
sendCh: msgSendCh,
closed: false,
logPrefix: logPrefix,
Logger: log.NewPrefixLogger(logPrefix),
proxies: make(map[string]*ProxyWrapper),
sendCh: msgSendCh,
closed: false,
clientCfg: clientCfg,
serverUDPPort: serverUDPPort,
logPrefix: logPrefix,
Logger: log.NewPrefixLogger(logPrefix),
}
}
@ -126,7 +133,7 @@ func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
addPxyNames := make([]string, 0)
for name, cfg := range pxyCfgs {
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
addPxyNames = append(addPxyNames, name)

View File

@ -65,7 +65,7 @@ type ProxyWrapper struct {
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()
pw := &ProxyWrapper{
ProxyStatus: ProxyStatus{
@ -90,7 +90,7 @@ func NewProxyWrapper(cfg config.ProxyConf, eventHandler event.EventHandler, logP
pw.Trace("enable health check monitor")
}
pw.pxy = NewProxy(pw.Cfg)
pw.pxy = NewProxy(pw.Cfg, clientCfg, serverUDPPort)
return pw
}

View File

@ -24,7 +24,6 @@ import (
"time"
"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/utils/log"
@ -35,6 +34,7 @@ import (
fmux "github.com/hashicorp/yamux"
)
// Service is a client service.
type Service struct {
// uniq id got from frps, attach it in loginMsg
runId string
@ -43,23 +43,27 @@ type Service struct {
ctl *Control
ctlMu sync.RWMutex
cfg config.ClientCommonConf
pxyCfgs map[string]config.ProxyConf
visitorCfgs map[string]config.VisitorConf
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
closedCh chan int
}
func NewService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (svr *Service, err error) {
// Init assets
err = assets.Load("")
if err != nil {
err = fmt.Errorf("Load assets error: %v", err)
return
}
// NewService creates a new client service with the given configuration.
func NewService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (svr *Service, err error) {
svr = &Service{
cfg: cfg,
cfgFile: cfgFile,
pxyCfgs: pxyCfgs,
visitorCfgs: visitorCfgs,
exit: 0,
@ -83,14 +87,14 @@ func (svr *Service) Run() error {
// if login_fail_exit is true, just exit this program
// otherwise sleep a while and try again to connect to server
if g.GlbClientCfg.LoginFailExit {
if svr.cfg.LoginFailExit {
return err
} else {
time.Sleep(10 * time.Second)
}
} else {
// 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()
svr.ctlMu.Lock()
svr.ctl = ctl
@ -101,12 +105,18 @@ func (svr *Service) Run() error {
go svr.keepControllerWorking()
if g.GlbClientCfg.AdminPort != 0 {
err := svr.RunAdminServer(g.GlbClientCfg.AdminAddr, g.GlbClientCfg.AdminPort)
if svr.cfg.AdminPort != 0 {
// 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 {
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
@ -138,7 +148,7 @@ func (svr *Service) keepControllerWorking() {
// reconnect success, init delayTime
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()
svr.ctlMu.Lock()
svr.ctl = ctl
@ -153,13 +163,13 @@ func (svr *Service) keepControllerWorking() {
// session: if it's not nil, using tcp mux
func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error) {
var tlsConfig *tls.Config
if g.GlbClientCfg.TLSEnable {
if svr.cfg.TLSEnable {
tlsConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
conn, err = frpNet.ConnectServerByProxyWithTLS(g.GlbClientCfg.HttpProxy, g.GlbClientCfg.Protocol,
fmt.Sprintf("%s:%d", g.GlbClientCfg.ServerAddr, g.GlbClientCfg.ServerPort), tlsConfig)
conn, err = frpNet.ConnectServerByProxyWithTLS(svr.cfg.HttpProxy, svr.cfg.Protocol,
fmt.Sprintf("%s:%d", svr.cfg.ServerAddr, svr.cfg.ServerPort), tlsConfig)
if err != nil {
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.KeepAliveInterval = 20 * time.Second
fmuxCfg.LogOutput = ioutil.Discard
@ -194,10 +204,10 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
loginMsg := &msg.Login{
Arch: runtime.GOARCH,
Os: runtime.GOOS,
PoolCount: g.GlbClientCfg.PoolCount,
User: g.GlbClientCfg.User,
PoolCount: svr.cfg.PoolCount,
User: svr.cfg.User,
Version: version.Full(),
PrivilegeKey: util.GetAuthKey(g.GlbClientCfg.Token, now),
PrivilegeKey: util.GetAuthKey(svr.cfg.Token, now),
Timestamp: now,
RunId: svr.runId,
}
@ -220,7 +230,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
}
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)
return
}

View File

@ -23,7 +23,6 @@ import (
"sync"
"time"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/utils/log"
@ -193,13 +192,13 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
defer userConn.Close()
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")
return
}
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 {
sv.Error("resolve server UDP addr error")
return

View File

@ -15,6 +15,9 @@
package main
import (
"math/rand"
"time"
_ "github.com/fatedier/frp/assets/frpc/statik"
"github.com/fatedier/frp/cmd/frpc/sub"
@ -23,6 +26,7 @@ import (
func main() {
crypto.DefaultSalt = "frp"
rand.Seed(time.Now().UnixNano())
sub.Execute()
}

View File

@ -33,6 +33,7 @@ func init() {
httpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
httpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
httpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
@ -53,7 +54,7 @@ var httpCmd = &cobra.Command{
Use: "http",
Short: "Run frpc with a single http proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -86,7 +87,7 @@ var httpCmd = &cobra.Command{
proxyConfs := map[string]config.ProxyConf{
cfg.ProxyName: cfg,
}
err = startService(proxyConfs, nil)
err = startService(clientCfg, proxyConfs, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -33,6 +33,7 @@ func init() {
httpsCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
httpsCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
httpsCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
@ -49,7 +50,7 @@ var httpsCmd = &cobra.Command{
Use: "https",
Short: "Run frpc with a single https proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -78,7 +79,7 @@ var httpsCmd = &cobra.Command{
proxyConfs := map[string]config.ProxyConf{
cfg.ProxyName: cfg,
}
err = startService(proxyConfs, nil)
err = startService(clientCfg, proxyConfs, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -24,7 +24,6 @@ import (
"github.com/spf13/cobra"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
)
@ -42,13 +41,13 @@ var reloadCmd = &cobra.Command{
os.Exit(1)
}
err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = reload()
err = reload(clientCfg)
if err != nil {
fmt.Printf("frpc reload error: %v\n", err)
os.Exit(1)
@ -58,19 +57,19 @@ var reloadCmd = &cobra.Command{
},
}
func reload() error {
if g.GlbClientCfg.AdminPort == 0 {
func reload(clientCfg config.ClientCommonConf) error {
if clientCfg.AdminPort == 0 {
return fmt.Errorf("admin_port shoud be set if you want to use reload feature")
}
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 {
return err
}
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
g.GlbClientCfg.AdminPwd))
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
clientCfg.AdminPwd))
req.Header.Add("Authorization", authStr)
resp, err := http.DefaultClient.Do(req)

View File

@ -28,7 +28,6 @@ import (
"github.com/spf13/cobra"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/utils/log"
"github.com/fatedier/frp/utils/version"
@ -43,13 +42,14 @@ var (
cfgFile string
showVersion bool
serverAddr string
user string
protocol string
token string
logLevel string
logFile string
logMaxDays int
serverAddr string
user string
protocol string
token string
logLevel string
logFile string
logMaxDays int
disableLogColor bool
proxyName string
localIp string
@ -113,59 +113,62 @@ func handleSignal(svr *client.Service) {
close(kcpDoneCh)
}
func parseClientCommonCfg(fileType int, content string) (err error) {
func parseClientCommonCfg(fileType int, content string) (cfg config.ClientCommonConf, err error) {
if fileType == CfgFileTypeIni {
err = parseClientCommonCfgFromIni(content)
cfg, err = parseClientCommonCfgFromIni(content)
} else if fileType == CfgFileTypeCmd {
err = parseClientCommonCfgFromCmd()
cfg, err = parseClientCommonCfgFromCmd()
}
if err != nil {
return
}
err = g.GlbClientCfg.ClientCommonConf.Check()
err = cfg.Check()
if err != nil {
return
}
return
}
func parseClientCommonCfgFromIni(content string) (err error) {
cfg, err := config.UnmarshalClientConfFromIni(&g.GlbClientCfg.ClientCommonConf, content)
func parseClientCommonCfgFromIni(content string) (config.ClientCommonConf, error) {
cfg, err := config.UnmarshalClientConfFromIni(content)
if err != nil {
return err
return config.ClientCommonConf{}, err
}
g.GlbClientCfg.ClientCommonConf = *cfg
return
return cfg, err
}
func parseClientCommonCfgFromCmd() (err error) {
func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
cfg = config.GetDefaultClientConf()
strs := strings.Split(serverAddr, ":")
if len(strs) < 2 {
err = fmt.Errorf("invalid server_addr")
return
}
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 {
err = fmt.Errorf("invalid server_addr")
return
}
g.GlbClientCfg.User = user
g.GlbClientCfg.Protocol = protocol
g.GlbClientCfg.Token = token
g.GlbClientCfg.LogLevel = logLevel
g.GlbClientCfg.LogFile = logFile
g.GlbClientCfg.LogMaxDays = int64(logMaxDays)
cfg.User = user
cfg.Protocol = protocol
cfg.Token = token
cfg.LogLevel = logLevel
cfg.LogFile = logFile
cfg.LogMaxDays = int64(logMaxDays)
if logFile == "console" {
g.GlbClientCfg.LogWay = "console"
cfg.LogWay = "console"
} else {
g.GlbClientCfg.LogWay = "file"
cfg.LogWay = "file"
}
return nil
cfg.DisableLogColor = disableLogColor
return
}
func runClient(cfgFilePath string) (err error) {
@ -174,26 +177,27 @@ func runClient(cfgFilePath string) (err error) {
if err != nil {
return
}
g.GlbClientCfg.CfgFile = cfgFilePath
err = parseClientCommonCfg(CfgFileTypeIni, content)
cfg, err := parseClientCommonCfg(CfgFileTypeIni, content)
if err != nil {
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 {
return err
}
err = startService(pxyCfgs, visitorCfgs)
err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)
return
}
func startService(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) (err error) {
log.InitLog(g.GlbClientCfg.LogWay, g.GlbClientCfg.LogFile, g.GlbClientCfg.LogLevel, g.GlbClientCfg.LogMaxDays)
if g.GlbClientCfg.DnsServer != "" {
s := g.GlbClientCfg.DnsServer
func startService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (err error) {
log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel,
cfg.LogMaxDays, cfg.DisableLogColor)
if cfg.DnsServer != "" {
s := cfg.DnsServer
if !strings.Contains(s, ":") {
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 {
err = errRet
return
}
// Capture the exit signal if we use kcp.
if g.GlbClientCfg.Protocol == "kcp" {
if cfg.Protocol == "kcp" {
go handleSignal(svr)
}
err = svr.Run()
if g.GlbClientCfg.Protocol == "kcp" {
if cfg.Protocol == "kcp" {
<-kcpDoneCh
}
return

View File

@ -27,7 +27,6 @@ import (
"github.com/spf13/cobra"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
)
@ -45,13 +44,13 @@ var statusCmd = &cobra.Command{
os.Exit(1)
}
err = parseClientCommonCfg(CfgFileTypeIni, iniContent)
clientCfg, err := parseClientCommonCfg(CfgFileTypeIni, iniContent)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
err = status()
err = status(clientCfg)
if err != nil {
fmt.Printf("frpc get status error: %v\n", err)
os.Exit(1)
@ -60,19 +59,19 @@ var statusCmd = &cobra.Command{
},
}
func status() error {
if g.GlbClientCfg.AdminPort == 0 {
func status(clientCfg config.ClientCommonConf) error {
if clientCfg.AdminPort == 0 {
return fmt.Errorf("admin_port shoud be set if you want to get proxy status")
}
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 {
return err
}
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(g.GlbClientCfg.AdminUser+":"+
g.GlbClientCfg.AdminPwd))
authStr := "Basic " + base64.StdEncoding.EncodeToString([]byte(clientCfg.AdminUser+":"+
clientCfg.AdminPwd))
req.Header.Add("Authorization", authStr)
resp, err := http.DefaultClient.Do(req)

View File

@ -32,6 +32,7 @@ func init() {
stcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
stcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
stcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
@ -51,7 +52,7 @@ var stcpCmd = &cobra.Command{
Use: "stcp",
Short: "Run frpc with a single stcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -103,7 +104,7 @@ var stcpCmd = &cobra.Command{
os.Exit(1)
}
err = startService(proxyConfs, visitorConfs)
err = startService(clientCfg, proxyConfs, visitorConfs, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -32,6 +32,7 @@ func init() {
tcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
tcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
tcpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
@ -47,7 +48,7 @@ var tcpCmd = &cobra.Command{
Use: "tcp",
Short: "Run frpc with a single tcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -75,7 +76,7 @@ var tcpCmd = &cobra.Command{
proxyConfs := map[string]config.ProxyConf{
cfg.ProxyName: cfg,
}
err = startService(proxyConfs, nil)
err = startService(clientCfg, proxyConfs, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -32,6 +32,7 @@ func init() {
udpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
udpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
udpCmd.PersistentFlags().StringVarP(&localIp, "local_ip", "i", "127.0.0.1", "local ip")
@ -47,7 +48,7 @@ var udpCmd = &cobra.Command{
Use: "udp",
Short: "Run frpc with a single udp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -75,7 +76,7 @@ var udpCmd = &cobra.Command{
proxyConfs := map[string]config.ProxyConf{
cfg.ProxyName: cfg,
}
err = startService(proxyConfs, nil)
err = startService(clientCfg, proxyConfs, nil, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -32,6 +32,7 @@ func init() {
xtcpCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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().BoolVarP(&disableLogColor, "disable_log_color", "", false, "disable log color in console")
xtcpCmd.PersistentFlags().StringVarP(&proxyName, "proxy_name", "n", "", "proxy name")
xtcpCmd.PersistentFlags().StringVarP(&role, "role", "", "server", "role")
@ -51,7 +52,7 @@ var xtcpCmd = &cobra.Command{
Use: "xtcp",
Short: "Run frpc with a single xtcp proxy",
RunE: func(cmd *cobra.Command, args []string) error {
err := parseClientCommonCfg(CfgFileTypeCmd, "")
clientCfg, err := parseClientCommonCfg(CfgFileTypeCmd, "")
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -103,7 +104,7 @@ var xtcpCmd = &cobra.Command{
os.Exit(1)
}
err = startService(proxyConfs, visitorConfs)
err = startService(clientCfg, proxyConfs, visitorConfs, "")
if err != nil {
fmt.Println(err)
os.Exit(1)

View File

@ -15,6 +15,9 @@
package main
import (
"math/rand"
"time"
"github.com/fatedier/golib/crypto"
_ "github.com/fatedier/frp/assets/frps/statik"
@ -22,6 +25,7 @@ import (
func main() {
crypto.DefaultSalt = "frp"
rand.Seed(time.Now().UnixNano())
Execute()
}

View File

@ -20,7 +20,6 @@ import (
"github.com/spf13/cobra"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/server"
"github.com/fatedier/frp/utils/log"
@ -53,6 +52,7 @@ var (
logFile string
logLevel string
logMaxDays int64
disableLogColor bool
token string
subDomainHost string
tcpMux bool
@ -80,6 +80,8 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&logFile, "log_file", "", "console", "log file")
rootCmd.PersistentFlags().StringVarP(&logLevel, "log_level", "", "info", "log level")
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(&subDomainHost, "subdomain_host", "", "", "subdomain host")
rootCmd.PersistentFlags().StringVarP(&allowPorts, "allow_ports", "", "", "allow ports")
@ -95,6 +97,7 @@ var rootCmd = &cobra.Command{
return nil
}
var cfg config.ServerCommonConf
var err error
if cfgFile != "" {
var content string
@ -102,16 +105,15 @@ var rootCmd = &cobra.Command{
if err != nil {
return err
}
g.GlbServerCfg.CfgFile = cfgFile
err = parseServerCommonCfg(CfgFileTypeIni, content)
cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
} else {
err = parseServerCommonCfg(CfgFileTypeCmd, "")
cfg, err = parseServerCommonCfg(CfgFileTypeCmd, "")
}
if err != nil {
return err
}
err = runServer()
err = runServer(cfg)
if err != nil {
fmt.Println(err)
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 {
err = parseServerCommonCfgFromIni(content)
cfg, err = parseServerCommonCfgFromIni(content)
} else if fileType == CfgFileTypeCmd {
err = parseServerCommonCfgFromCmd()
cfg, err = parseServerCommonCfgFromCmd()
}
if err != nil {
return
}
err = g.GlbServerCfg.ServerCommonConf.Check()
err = cfg.Check()
if err != nil {
return
}
config.InitServerCfg(&g.GlbServerCfg.ServerCommonConf)
return
}
func parseServerCommonCfgFromIni(content string) (err error) {
cfg, err := config.UnmarshalServerConfFromIni(&g.GlbServerCfg.ServerCommonConf, content)
func parseServerCommonCfgFromIni(content string) (config.ServerCommonConf, error) {
cfg, err := config.UnmarshalServerConfFromIni(content)
if err != nil {
return err
return config.ServerCommonConf{}, err
}
g.GlbServerCfg.ServerCommonConf = *cfg
return
return cfg, nil
}
func parseServerCommonCfgFromCmd() (err error) {
g.GlbServerCfg.BindAddr = bindAddr
g.GlbServerCfg.BindPort = bindPort
g.GlbServerCfg.BindUdpPort = bindUdpPort
g.GlbServerCfg.KcpBindPort = kcpBindPort
g.GlbServerCfg.ProxyBindAddr = proxyBindAddr
g.GlbServerCfg.VhostHttpPort = vhostHttpPort
g.GlbServerCfg.VhostHttpsPort = vhostHttpsPort
g.GlbServerCfg.VhostHttpTimeout = vhostHttpTimeout
g.GlbServerCfg.DashboardAddr = dashboardAddr
g.GlbServerCfg.DashboardPort = dashboardPort
g.GlbServerCfg.DashboardUser = dashboardUser
g.GlbServerCfg.DashboardPwd = dashboardPwd
g.GlbServerCfg.LogFile = logFile
g.GlbServerCfg.LogLevel = logLevel
g.GlbServerCfg.LogMaxDays = logMaxDays
g.GlbServerCfg.Token = token
g.GlbServerCfg.SubDomainHost = subDomainHost
func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
cfg = config.GetDefaultServerConf()
cfg.BindAddr = bindAddr
cfg.BindPort = bindPort
cfg.BindUdpPort = bindUdpPort
cfg.KcpBindPort = kcpBindPort
cfg.ProxyBindAddr = proxyBindAddr
cfg.VhostHttpPort = vhostHttpPort
cfg.VhostHttpsPort = vhostHttpsPort
cfg.VhostHttpTimeout = vhostHttpTimeout
cfg.DashboardAddr = dashboardAddr
cfg.DashboardPort = dashboardPort
cfg.DashboardUser = dashboardUser
cfg.DashboardPwd = dashboardPwd
cfg.LogFile = logFile
cfg.LogLevel = logLevel
cfg.LogMaxDays = logMaxDays
cfg.Token = token
cfg.SubDomainHost = subDomainHost
if len(allowPorts) > 0 {
// e.g. 1000-2000,2001,2002,3000-4000
ports, errRet := util.ParseRangeNumbers(allowPorts)
@ -181,28 +182,27 @@ func parseServerCommonCfgFromCmd() (err error) {
}
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" {
g.GlbServerCfg.LogWay = "console"
cfg.LogWay = "console"
} else {
g.GlbServerCfg.LogWay = "file"
cfg.LogWay = "file"
}
cfg.DisableLogColor = disableLogColor
return
}
func runServer() (err error) {
log.InitLog(g.GlbServerCfg.LogWay, g.GlbServerCfg.LogFile, g.GlbServerCfg.LogLevel,
g.GlbServerCfg.LogMaxDays)
svr, err := server.NewService()
func runServer(cfg config.ServerCommonConf) (err error) {
log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel, cfg.LogMaxDays, cfg.DisableLogColor)
svr, err := server.NewService(cfg)
if err != nil {
return err
}
log.Info("Start frps success")
server.ServerService = svr
svr.Run()
return
}

View File

@ -18,6 +18,9 @@ log_level = info
log_max_days = 3
# disable log colors when log_file is console, default is false
disable_log_color = false
# for authentication
token = 12345678
@ -26,6 +29,8 @@ admin_addr = 127.0.0.1
admin_port = 7400
admin_user = 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
pool_count = 5
@ -198,6 +203,7 @@ plugin_local_addr = 127.0.0.1:80
plugin_crt_path = ./server.crt
plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
[secret_tcp]
# If the type is secret tcp, remote_port is useless

View File

@ -43,6 +43,9 @@ log_level = info
log_max_days = 3
# disable log colors when log_file is console, default is false
disable_log_color = false
# auth token
token = 12345678

32
g/g.go
View File

@ -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
View File

@ -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/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/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb h1:wCrNShQidLmvVWn/0PikGmpdP0vtQmnvyRg3ZBEhczw=
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/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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
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/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=

View File

@ -23,34 +23,103 @@ import (
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 {
ServerAddr string `json:"server_addr"`
ServerPort int `json:"server_port"`
HttpProxy string `json:"http_proxy"`
LogFile string `json:"log_file"`
LogWay string `json:"log_way"`
LogLevel string `json:"log_level"`
LogMaxDays int64 `json:"log_max_days"`
Token string `json:"token"`
AdminAddr string `json:"admin_addr"`
AdminPort int `json:"admin_port"`
AdminUser string `json:"admin_user"`
AdminPwd string `json:"admin_pwd"`
PoolCount int `json:"pool_count"`
TcpMux bool `json:"tcp_mux"`
User string `json:"user"`
DnsServer string `json:"dns_server"`
LoginFailExit bool `json:"login_fail_exit"`
Start map[string]struct{} `json:"start"`
Protocol string `json:"protocol"`
TLSEnable bool `json:"tls_enable"`
HeartBeatInterval int64 `json:"heartbeat_interval"`
HeartBeatTimeout int64 `json:"heartbeat_timeout"`
// ServerAddr specifies the address of the server to connect to. By
// default, this value is "0.0.0.0".
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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// AdminAddr specifies the address that the admin server binds to. By
// default, this value is "127.0.0.1".
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"`
// AdminUser specifies the username that the admin server will use for
// login. By default, this value is "admin".
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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// TLSEnable specifies whether or not TLS should be used when communicating
// with the server.
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"`
// 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"`
}
func GetDefaultClientConf() *ClientCommonConf {
return &ClientCommonConf{
// GetDefaultClientConf returns a client configuration with default values.
func GetDefaultClientConf() ClientCommonConf {
return ClientCommonConf{
ServerAddr: "0.0.0.0",
ServerPort: 7000,
HttpProxy: os.Getenv("http_proxy"),
@ -58,11 +127,13 @@ func GetDefaultClientConf() *ClientCommonConf {
LogWay: "console",
LogLevel: "info",
LogMaxDays: 3,
DisableLogColor: false,
Token: "",
AdminAddr: "127.0.0.1",
AdminPort: 0,
AdminUser: "",
AdminPwd: "",
AssetsDir: "",
PoolCount: 1,
TcpMux: true,
User: "",
@ -76,16 +147,12 @@ func GetDefaultClientConf() *ClientCommonConf {
}
}
func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (cfg *ClientCommonConf, err error) {
cfg = defaultCfg
if cfg == nil {
cfg = GetDefaultClientConf()
}
func UnmarshalClientConfFromIni(content string) (cfg ClientCommonConf, err error) {
cfg = GetDefaultClientConf()
conf, err := ini.Load(strings.NewReader(content))
if err != nil {
err = fmt.Errorf("parse ini conf file error: %v", err)
return nil, err
return ClientCommonConf{}, fmt.Errorf("parse ini conf file error: %v", err)
}
var (
@ -106,6 +173,10 @@ func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (c
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 {
cfg.HttpProxy = tmpStr
}
@ -154,6 +225,10 @@ func UnmarshalClientConfFromIni(defaultCfg *ClientCommonConf, content string) (c
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 v, err = strconv.ParseInt(tmpStr, 10, 64); err == nil {
cfg.PoolCount = int(v)

View File

@ -58,11 +58,11 @@ type ProxyConf interface {
UnmarshalFromIni(prefix string, name string, conf ini.Section) error
MarshalToMsg(pMsg *msg.NewProxy)
CheckForCli() error
CheckForSvr() error
CheckForSvr(serverCfg ServerCommonConf) error
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 == "" {
pMsg.ProxyType = consts.TcpProxy
}
@ -73,7 +73,7 @@ func NewProxyConfFromMsg(pMsg *msg.NewProxy) (cfg ProxyConf, err error) {
return
}
cfg.UnmarshalFromMsg(pMsg)
err = cfg.CheckForSvr()
err = cfg.CheckForSvr(serverCfg)
return
}
@ -97,17 +97,33 @@ func NewProxyConfFromIni(prefix string, name string, section ini.Section) (cfg P
return
}
// BaseProxy info
// BaseProxyConf provides configuration info that is common to all proxy types.
type BaseProxyConf struct {
// ProxyName is the name of this proxy.
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"`
UseEncryption bool `json:"use_encryption"`
UseCompression bool `json:"use_compression"`
Group string `json:"group"`
GroupKey string `json:"group_key"`
// 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"`
// UseCompression controls whether or not communication with the server
// will be compressed. By default, this value is false.
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"`
// 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"`
// 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"`
LocalSvrConf
HealthCheckConf
@ -308,21 +324,21 @@ func (cfg *DomainConf) checkForCli() (err error) {
return
}
func (cfg *DomainConf) checkForSvr() (err error) {
func (cfg *DomainConf) checkForSvr(serverCfg ServerCommonConf) (err error) {
if err = cfg.check(); err != nil {
return
}
for _, domain := range cfg.CustomDomains {
if subDomainHost != "" && len(strings.Split(subDomainHost, ".")) < len(strings.Split(domain, ".")) {
if strings.Contains(domain, subDomainHost) {
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, subDomainHost)
if serverCfg.SubDomainHost != "" && len(strings.Split(serverCfg.SubDomainHost, ".")) < len(strings.Split(domain, ".")) {
if strings.Contains(domain, serverCfg.SubDomainHost) {
return fmt.Errorf("custom domain [%s] should not belong to subdomain_host [%s]", domain, serverCfg.SubDomainHost)
}
}
}
if cfg.SubDomain != "" {
if subDomainHost == "" {
if serverCfg.SubDomainHost == "" {
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, "*") {
@ -332,12 +348,20 @@ func (cfg *DomainConf) checkForSvr() (err error) {
return
}
// Local service info
// LocalSvrConf configures what location the client will proxy to, or what
// plugin will be used.
type LocalSvrConf struct {
LocalIp string `json:"local_ip"`
LocalPort int `json:"local_port"`
// LocalIp specifies the IP address or host name to proxy to.
LocalIp string `json:"local_ip"`
// LocalPort specifies the port to proxy to.
LocalPort int `json:"local_port"`
Plugin string `json:"plugin"`
// 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"`
// 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"`
}
@ -399,15 +423,35 @@ func (cfg *LocalSvrConf) checkForCli() (err error) {
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 {
HealthCheckType string `json:"health_check_type"` // tcp | http
HealthCheckTimeoutS int `json:"health_check_timeout_s"`
HealthCheckMaxFailed int `json:"health_check_max_failed"`
HealthCheckIntervalS int `json:"health_check_interval_s"`
HealthCheckUrl string `json:"health_check_url"`
// local_ip + local_port
// 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
// 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"`
// 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"`
// HealthCheckIntervalS specifies the time in seconds between health
// checks. By default, this value is 10.
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"`
// HealthCheckAddr specifies the address to connect to if the health check
// type is "tcp".
HealthCheckAddr string `json:"-"`
}
@ -504,7 +548,7 @@ func (cfg *TcpProxyConf) CheckForCli() (err error) {
return
}
func (cfg *TcpProxyConf) CheckForSvr() error { return nil }
func (cfg *TcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { return nil }
// UDP
type UdpProxyConf struct {
@ -552,7 +596,7 @@ func (cfg *UdpProxyConf) CheckForCli() (err error) {
return
}
func (cfg *UdpProxyConf) CheckForSvr() error { return nil }
func (cfg *UdpProxyConf) CheckForSvr(serverCfg ServerCommonConf) error { return nil }
// HTTP
type HttpProxyConf struct {
@ -657,11 +701,11 @@ func (cfg *HttpProxyConf) CheckForCli() (err error) {
return
}
func (cfg *HttpProxyConf) CheckForSvr() (err error) {
if vhostHttpPort == 0 {
func (cfg *HttpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if serverCfg.VhostHttpPort == 0 {
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)
return
}
@ -717,11 +761,11 @@ func (cfg *HttpsProxyConf) CheckForCli() (err error) {
return
}
func (cfg *HttpsProxyConf) CheckForSvr() (err error) {
if vhostHttpsPort == 0 {
func (cfg *HttpsProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
if serverCfg.VhostHttpsPort == 0 {
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)
return
}
@ -790,7 +834,7 @@ func (cfg *StcpProxyConf) CheckForCli() (err error) {
return
}
func (cfg *StcpProxyConf) CheckForSvr() (err error) {
func (cfg *StcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
return
}
@ -857,7 +901,7 @@ func (cfg *XtcpProxyConf) CheckForCli() (err error) {
return
}
func (cfg *XtcpProxyConf) CheckForSvr() (err error) {
func (cfg *XtcpProxyConf) CheckForSvr(serverCfg ServerCommonConf) (err error) {
return
}

View File

@ -24,62 +24,122 @@ import (
"github.com/fatedier/frp/utils/util"
)
var (
// server global configure used for generate proxy conf used in frps
proxyBindAddr string
subDomainHost string
vhostHttpPort int
vhostHttpsPort int
)
func InitServerCfg(cfg *ServerCommonConf) {
proxyBindAddr = cfg.ProxyBindAddr
subDomainHost = cfg.SubDomainHost
vhostHttpPort = cfg.VhostHttpPort
vhostHttpsPort = cfg.VhostHttpsPort
}
// common config
// ServerCommonConf contains information for a server service. It is
// recommended to use GetDefaultServerConf instead of creating this object
// directly, so that all unspecified fields have reasonable default values.
type ServerCommonConf struct {
BindAddr string `json:"bind_addr"`
BindPort int `json:"bind_port"`
BindUdpPort int `json:"bind_udp_port"`
KcpBindPort int `json:"kcp_bind_port"`
// BindAddr specifies the address that the server binds to. By default,
// this value is "0.0.0.0".
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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
// DashboardAddr specifies the address that the dashboard binds to. By
// default, this value is "0.0.0.0".
DashboardAddr string `json:"dashboard_addr"`
// if DashboardPort equals 0, dashboard is not available
DashboardPort int `json:"dashboard_port"`
// 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"`
// DashboardUser specifies the username that the dashboard will use for
// login. By default, this value is "admin".
DashboardUser string `json:"dashboard_user"`
DashboardPwd string `json:"dashboard_pwd"`
AssetsDir string `json:"asserts_dir"`
LogFile string `json:"log_file"`
LogWay string `json:"log_way"` // console or file
LogLevel string `json:"log_level"`
LogMaxDays int64 `json:"log_max_days"`
Token string `json:"token"`
// DashboardUser specifies the password that the dashboard will use for
// login. By default, this value is "admin".
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"`
// 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"`
// 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"`
// 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"`
// 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"`
// 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"`
TcpMux bool `json:"tcp_mux"`
// 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"`
// 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"`
AllowPorts map[int]struct{}
MaxPoolCount int64 `json:"max_pool_count"`
// 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{}
// MaxPoolCount specifies the maximum pool size for each proxy. By default,
// this value is 5.
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"`
HeartBeatTimeout int64 `json:"heart_beat_timeout"`
UserConnTimeout int64 `json:"user_conn_timeout"`
// 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"`
// UserConnTimeout specifies the maximum time to wait for a work
// connection. By default, this value is 10.
UserConnTimeout int64 `json:"user_conn_timeout"`
}
func GetDefaultServerConf() *ServerCommonConf {
return &ServerCommonConf{
// GetDefaultServerConf returns a server configuration with reasonable
// defaults.
func GetDefaultServerConf() ServerCommonConf {
return ServerCommonConf{
BindAddr: "0.0.0.0",
BindPort: 7000,
BindUdpPort: 0,
@ -97,6 +157,7 @@ func GetDefaultServerConf() *ServerCommonConf {
LogWay: "console",
LogLevel: "info",
LogMaxDays: 3,
DisableLogColor: false,
Token: "",
SubDomainHost: "",
TcpMux: true,
@ -109,16 +170,15 @@ func GetDefaultServerConf() *ServerCommonConf {
}
}
func UnmarshalServerConfFromIni(defaultCfg *ServerCommonConf, content string) (cfg *ServerCommonConf, err error) {
cfg = defaultCfg
if cfg == nil {
cfg = GetDefaultServerConf()
}
// UnmarshalServerConfFromIni parses the contents of a server configuration ini
// file and returns the resulting server configuration.
func UnmarshalServerConfFromIni(content string) (cfg ServerCommonConf, err error) {
cfg = GetDefaultServerConf()
conf, err := ini.Load(strings.NewReader(content))
if err != nil {
err = fmt.Errorf("parse ini conf file error: %v", err)
return nil, err
return ServerCommonConf{}, err
}
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")
if allowPortsStr, ok := conf.Get("common", "allow_ports"); ok {

View File

@ -20,6 +20,7 @@ import (
"io"
"net/http"
"net/http/httputil"
"strings"
frpNet "github.com/fatedier/frp/utils/net"
)
@ -35,6 +36,7 @@ type HTTPS2HTTPPlugin struct {
keyPath string
hostHeaderRewrite string
localAddr string
headers map[string]string
l *Listener
s *http.Server
@ -45,6 +47,15 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
keyPath := params["plugin_key_path"]
localAddr := params["plugin_local_addr"]
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 == "" {
return nil, fmt.Errorf("plugin_crt_path is required")
@ -63,6 +74,7 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
keyPath: keyPath,
localAddr: localAddr,
hostHeaderRewrite: hostHeaderRewrite,
headers: headers,
l: listener,
}
@ -73,6 +85,9 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
if p.hostHeaderRewrite != "" {
req.Host = p.hostHeaderRewrite
}
for k, v := range p.headers {
req.Header.Set(k, v)
}
},
}

View File

@ -21,7 +21,6 @@ import (
"sync"
"time"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/consts"
frpErr "github.com/fatedier/frp/models/errors"
@ -129,11 +128,19 @@ type Control struct {
allShutdown *shutdown.Shutdown
mu sync.RWMutex
// Server configuration information
serverCfg config.ServerCommonConf
}
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{
rc: rc,
pxyManager: pxyManager,
@ -142,9 +149,9 @@ func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManage
loginMsg: loginMsg,
sendCh: 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),
poolCount: loginMsg.PoolCount,
poolCount: poolCount,
portsUsedNum: 0,
lastPing: time.Now(),
runId: loginMsg.RunId,
@ -153,6 +160,7 @@ func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManage
writerShutdown: shutdown.New(),
managerShutdown: shutdown.New(),
allShutdown: shutdown.New(),
serverCfg: serverCfg,
}
}
@ -161,7 +169,7 @@ func (ctl *Control) Start() {
loginRespMsg := &msg.LoginResp{
Version: version.Full(),
RunId: ctl.runId,
ServerUdpPort: g.GlbServerCfg.BindUdpPort,
ServerUdpPort: ctl.serverCfg.BindUdpPort,
Error: "",
}
msg.WriteMsg(ctl.conn, loginRespMsg)
@ -232,7 +240,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
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")
ctl.conn.Warn("%v", err)
return
@ -263,7 +271,7 @@ func (ctl *Control) writer() {
defer ctl.allShutdown.Start()
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 {
ctl.conn.Error("crypto new writer error: %v", err)
ctl.allShutdown.Start()
@ -293,7 +301,7 @@ func (ctl *Control) reader() {
defer ctl.allShutdown.Start()
defer ctl.readerShutdown.Done()
encReader := crypto.NewReader(ctl.conn, []byte(g.GlbServerCfg.Token))
encReader := crypto.NewReader(ctl.conn, []byte(ctl.serverCfg.Token))
for {
if m, err := msg.ReadMsg(encReader); err != nil {
if err == io.EOF {
@ -374,7 +382,7 @@ func (ctl *Control) manager() {
for {
select {
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")
return
}
@ -417,22 +425,22 @@ func (ctl *Control) manager() {
func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err error) {
var pxyConf config.ProxyConf
// Load configures from NewProxy message and check.
pxyConf, err = config.NewProxyConfFromMsg(pxyMsg)
pxyConf, err = config.NewProxyConfFromMsg(pxyMsg, ctl.serverCfg)
if err != nil {
return
}
// NewProxy will return a interface Proxy.
// 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 {
return remoteAddr, err
}
// Check ports used number in each client
if g.GlbServerCfg.MaxPortsPerClient > 0 {
if ctl.serverCfg.MaxPortsPerClient > 0 {
ctl.mu.Lock()
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(g.GlbServerCfg.MaxPortsPerClient) {
if ctl.portsUsedNum+pxy.GetUsedPortsNum() > int(ctl.serverCfg.MaxPortsPerClient) {
ctl.mu.Unlock()
err = fmt.Errorf("exceed the max_ports_per_client")
return
@ -478,7 +486,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
return
}
if g.GlbServerCfg.MaxPortsPerClient > 0 {
if ctl.serverCfg.MaxPortsPerClient > 0 {
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
}
pxy.Close()

View File

@ -21,7 +21,6 @@ import (
"time"
"github.com/fatedier/frp/assets"
"github.com/fatedier/frp/g"
frpNet "github.com/fatedier/frp/utils/net"
"github.com/gorilla/mux"
@ -36,7 +35,7 @@ func (svr *Service) RunDashboardServer(addr string, port int) (err error) {
// url router
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)
// api, see dashboard_api.go

View File

@ -18,7 +18,6 @@ import (
"encoding/json"
"net/http"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/consts"
"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)
cfg := &g.GlbServerCfg.ServerCommonConf
serverStats := svr.statsCollector.GetServer()
svrResp := ServerInfoResp{
Version: version.Full(),
BindPort: cfg.BindPort,
BindUdpPort: cfg.BindUdpPort,
VhostHttpPort: cfg.VhostHttpPort,
VhostHttpsPort: cfg.VhostHttpsPort,
KcpBindPort: cfg.KcpBindPort,
SubdomainHost: cfg.SubDomainHost,
MaxPoolCount: cfg.MaxPoolCount,
MaxPortsPerClient: cfg.MaxPortsPerClient,
HeartBeatTimeout: cfg.HeartBeatTimeout,
BindPort: svr.cfg.BindPort,
BindUdpPort: svr.cfg.BindUdpPort,
VhostHttpPort: svr.cfg.VhostHttpPort,
VhostHttpsPort: svr.cfg.VhostHttpsPort,
KcpBindPort: svr.cfg.KcpBindPort,
SubdomainHost: svr.cfg.SubDomainHost,
MaxPoolCount: svr.cfg.MaxPoolCount,
MaxPortsPerClient: svr.cfg.MaxPortsPerClient,
HeartBeatTimeout: svr.cfg.HeartBeatTimeout,
TotalTrafficIn: serverStats.TotalTrafficIn,
TotalTrafficOut: serverStats.TotalTrafficOut,

View File

@ -19,7 +19,6 @@ import (
"net"
"strings"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/server/stats"
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)
})
}
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)
}
}
if pxy.cfg.SubDomain != "" {
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
for _, location := range locations {
routeConfig.Location = location
tmpDomain := routeConfig.Domain
@ -119,7 +118,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
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)
}
@ -147,7 +146,7 @@ func (pxy *HttpProxy) GetRealConn(remoteAddr string) (workConn frpNet.Conn, err
var rwc io.ReadWriteCloser = tmpConn
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 {
pxy.Error("create encryption stream error: %v", err)
return

View File

@ -17,7 +17,6 @@ package proxy
import (
"strings"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/utils/util"
"github.com/fatedier/frp/utils/vhost"
@ -51,11 +50,11 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
l.AddLogPrefix(pxy.name)
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
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 != "" {
routeConfig.Domain = pxy.cfg.SubDomain + "." + g.GlbServerCfg.SubDomainHost
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(routeConfig)
if errRet != nil {
err = errRet
@ -64,7 +63,7 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
l.AddLogPrefix(pxy.name)
pxy.Info("https proxy listen for host [%s]", routeConfig.Domain)
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)

View File

@ -21,7 +21,6 @@ import (
"strconv"
"sync"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/server/controller"
@ -52,6 +51,7 @@ type BaseProxy struct {
usedPortsNum int
poolCount int
getWorkConnFn GetWorkConnFn
serverCfg config.ServerCommonConf
mu sync.RWMutex
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.
// 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.
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 {
go func(l frpNet.Listener) {
for {
@ -138,14 +138,14 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, frpNet.Con
return
}
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)
}
}
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{
name: pxyConf.GetBaseInfo().ProxyName,
@ -155,6 +155,7 @@ func NewProxy(runId string, rc *controller.ResourceController, statsCollector st
poolCount: poolCount,
getWorkConnFn: getWorkConnFn,
Logger: log.NewPrefixLogger(runId),
serverCfg: serverCfg,
}
switch cfg := pxyConf.(type) {
case *config.TcpProxyConf:
@ -198,7 +199,7 @@ func NewProxy(runId string, rc *controller.ResourceController, statsCollector st
// HandleUserTcpConnection is used for incoming tcp user connections.
// 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()
// try all connections from the pool
@ -211,7 +212,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn, statsCollector sta
var local io.ReadWriteCloser = workConn
cfg := pxy.GetConf().GetBaseInfo()
if cfg.UseEncryption {
local, err = frpIo.WithEncryption(local, []byte(g.GlbServerCfg.Token))
local, err = frpIo.WithEncryption(local, []byte(serverCfg.Token))
if err != nil {
pxy.Error("create encryption stream error: %v", err)
return

View File

@ -17,7 +17,6 @@ package proxy
import (
"fmt"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
frpNet "github.com/fatedier/frp/utils/net"
)
@ -31,7 +30,7 @@ type TcpProxy struct {
func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
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 {
err = errRet
return
@ -56,7 +55,7 @@ func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
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 {
err = errRet
return

View File

@ -20,7 +20,6 @@ import (
"net"
"time"
"github.com/fatedier/frp/g"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"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)
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 {
err = errRet
return

View File

@ -29,7 +29,7 @@ import (
"time"
"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/nathole"
"github.com/fatedier/frp/server/controller"
@ -51,8 +51,6 @@ const (
connReadTimeout time.Duration = 10 * time.Second
)
var ServerService *Service
// Server service
type Service struct {
// Dispatch connections to different handlers listen on same port
@ -86,10 +84,11 @@ type Service struct {
statsCollector stats.Collector
tlsConfig *tls.Config
cfg config.ServerCommonConf
}
func NewService() (svr *Service, err error) {
cfg := &g.GlbServerCfg.ServerCommonConf
func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
svr = &Service{
ctlManager: NewControlManager(),
pxyManager: proxy.NewProxyManager(),
@ -100,6 +99,7 @@ func NewService() (svr *Service, err error) {
},
httpVhostRouter: vhost.NewVhostRouters(),
tlsConfig: generateTLSConfig(),
cfg: cfg,
}
// Init group controller
@ -108,13 +108,6 @@ func NewService() (svr *Service, err error) {
// Init HTTP group controller
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
vhost.NotFoundPagePath = cfg.Custom404Page
@ -231,6 +224,13 @@ func NewService() (svr *Service, err error) {
var statsEnable bool
// Create dashboard web server.
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)
if err != nil {
err = fmt.Errorf("Create dashboard web server error, %v", err)
@ -248,7 +248,7 @@ func (svr *Service) Run() {
if svr.rc.NatHoleController != nil {
go svr.rc.NatHoleController.Run()
}
if g.GlbServerCfg.KcpBindPort > 0 {
if svr.cfg.KcpBindPort > 0 {
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.KeepAliveInterval = 20 * time.Second
fmuxCfg.LogOutput = ioutil.Discard
@ -363,7 +363,7 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
}
// 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")
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 {
oldCtl.allShutdown.WaitDone()

View File

@ -67,6 +67,20 @@ custom_domains = test2.com
health_check_type = http
health_check_interval_s = 1
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) {
@ -124,6 +138,22 @@ func TestHealthCheck(t *testing.T) {
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)
// ****** start frps and frpc ******
@ -244,4 +274,20 @@ func TestHealthCheck(t *testing.T) {
assert.NoError(err)
assert.Equal(200, code)
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")
}

View File

@ -29,16 +29,20 @@ func init() {
Log.SetLogFuncCallDepth(Log.GetLogFuncCallDepth() + 1)
}
func InitLog(logWay string, logFile string, logLevel string, maxdays int64) {
SetLogFile(logWay, logFile, maxdays)
func InitLog(logWay string, logFile string, logLevel string, maxdays int64, disableLogColor bool) {
SetLogFile(logWay, logFile, maxdays, disableLogColor)
SetLogLevel(logLevel)
}
// SetLogFile to configure log params
// 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" {
Log.SetLogger("console", "")
params := ""
if disableLogColor {
params = fmt.Sprintf(`{"color": false}`)
}
Log.SetLogger("console", params)
} else {
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays)
Log.SetLogger("file", params)

View File

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