mirror of
https://github.com/fatedier/frp.git
synced 2024-11-24 02:59:19 +08:00
change log method
This commit is contained in:
parent
5dc8175fc8
commit
649f47c345
2
Makefile
2
Makefile
@ -16,7 +16,7 @@ file:
|
|||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
go fmt ./...
|
go fmt ./...
|
||||||
|
|
||||||
frps:
|
frps:
|
||||||
go build -o bin/frps ./cmd/frps
|
go build -o bin/frps ./cmd/frps
|
||||||
|
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -25,8 +27,8 @@ import (
|
|||||||
"github.com/fatedier/frp/client/proxy"
|
"github.com/fatedier/frp/client/proxy"
|
||||||
"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"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
"github.com/fatedier/golib/control/shutdown"
|
"github.com/fatedier/golib/control/shutdown"
|
||||||
"github.com/fatedier/golib/crypto"
|
"github.com/fatedier/golib/crypto"
|
||||||
@ -45,7 +47,7 @@ type Control struct {
|
|||||||
vm *VisitorManager
|
vm *VisitorManager
|
||||||
|
|
||||||
// control connection
|
// control connection
|
||||||
conn frpNet.Conn
|
conn net.Conn
|
||||||
|
|
||||||
// tcp stream multiplexing, if enabled
|
// tcp stream multiplexing, if enabled
|
||||||
session *fmux.Session
|
session *fmux.Session
|
||||||
@ -76,12 +78,19 @@ type Control struct {
|
|||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
log.Logger
|
xl *xlog.Logger
|
||||||
|
|
||||||
|
// service context
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, clientCfg config.ClientCommonConf,
|
func NewControl(ctx context.Context, runId string, conn net.Conn, session *fmux.Session,
|
||||||
pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, serverUDPPort int) *Control {
|
clientCfg config.ClientCommonConf,
|
||||||
|
pxyCfgs map[string]config.ProxyConf,
|
||||||
|
visitorCfgs map[string]config.VisitorConf,
|
||||||
|
serverUDPPort int) *Control {
|
||||||
|
|
||||||
|
// new xlog instance
|
||||||
ctl := &Control{
|
ctl := &Control{
|
||||||
runId: runId,
|
runId: runId,
|
||||||
conn: conn,
|
conn: conn,
|
||||||
@ -96,11 +105,12 @@ func NewControl(runId string, conn frpNet.Conn, session *fmux.Session, clientCfg
|
|||||||
writerShutdown: shutdown.New(),
|
writerShutdown: shutdown.New(),
|
||||||
msgHandlerShutdown: shutdown.New(),
|
msgHandlerShutdown: shutdown.New(),
|
||||||
serverUDPPort: serverUDPPort,
|
serverUDPPort: serverUDPPort,
|
||||||
Logger: log.NewPrefixLogger(""),
|
xl: xlog.FromContextSafe(ctx),
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
ctl.pm = proxy.NewProxyManager(ctl.sendCh, runId, clientCfg, serverUDPPort)
|
ctl.pm = proxy.NewProxyManager(ctl.ctx, ctl.sendCh, clientCfg, serverUDPPort)
|
||||||
|
|
||||||
ctl.vm = NewVisitorManager(ctl)
|
ctl.vm = NewVisitorManager(ctl.ctx, ctl)
|
||||||
ctl.vm.Reload(visitorCfgs)
|
ctl.vm.Reload(visitorCfgs)
|
||||||
return ctl
|
return ctl
|
||||||
}
|
}
|
||||||
@ -117,6 +127,7 @@ func (ctl *Control) Run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
|
func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
|
||||||
|
xl := ctl.xl
|
||||||
workConn, err := ctl.connectServer()
|
workConn, err := ctl.connectServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -126,31 +137,31 @@ func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
|
|||||||
RunId: ctl.runId,
|
RunId: ctl.runId,
|
||||||
}
|
}
|
||||||
if err = msg.WriteMsg(workConn, m); err != nil {
|
if err = msg.WriteMsg(workConn, m); err != nil {
|
||||||
ctl.Warn("work connection write to server error: %v", err)
|
xl.Warn("work connection write to server error: %v", err)
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var startMsg msg.StartWorkConn
|
var startMsg msg.StartWorkConn
|
||||||
if err = msg.ReadMsgInto(workConn, &startMsg); err != nil {
|
if err = msg.ReadMsgInto(workConn, &startMsg); err != nil {
|
||||||
ctl.Error("work connection closed, %v", err)
|
xl.Error("work connection closed before response StartWorkConn message: %v", err)
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
workConn.AddLogPrefix(startMsg.ProxyName)
|
|
||||||
|
|
||||||
// dispatch this work connection to related proxy
|
// dispatch this work connection to related proxy
|
||||||
ctl.pm.HandleWorkConn(startMsg.ProxyName, workConn, &startMsg)
|
ctl.pm.HandleWorkConn(startMsg.ProxyName, workConn, &startMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) {
|
func (ctl *Control) HandleNewProxyResp(inMsg *msg.NewProxyResp) {
|
||||||
|
xl := ctl.xl
|
||||||
// Server will return NewProxyResp message to each NewProxy message.
|
// Server will return NewProxyResp message to each NewProxy message.
|
||||||
// Start a new proxy handler if no error got
|
// Start a new proxy handler if no error got
|
||||||
err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error)
|
err := ctl.pm.StartProxy(inMsg.ProxyName, inMsg.RemoteAddr, inMsg.Error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.Warn("[%s] start error: %v", inMsg.ProxyName, err)
|
xl.Warn("[%s] start error: %v", inMsg.ProxyName, err)
|
||||||
} else {
|
} else {
|
||||||
ctl.Info("[%s] start proxy success", inMsg.ProxyName)
|
xl.Info("[%s] start proxy success", inMsg.ProxyName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,15 +180,16 @@ 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 net.Conn, err error) {
|
||||||
|
xl := ctl.xl
|
||||||
if ctl.clientCfg.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
|
||||||
ctl.Warn("start new connection to server error: %v", err)
|
xl.Warn("start new connection to server error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = frpNet.WrapConn(stream)
|
conn = stream
|
||||||
} else {
|
} else {
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if ctl.clientCfg.TLSEnable {
|
if ctl.clientCfg.TLSEnable {
|
||||||
@ -188,7 +200,7 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
|||||||
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HttpProxy, ctl.clientCfg.Protocol,
|
conn, err = frpNet.ConnectServerByProxyWithTLS(ctl.clientCfg.HttpProxy, ctl.clientCfg.Protocol,
|
||||||
fmt.Sprintf("%s:%d", ctl.clientCfg.ServerAddr, ctl.clientCfg.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)
|
xl.Warn("start new connection to server error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,10 +209,11 @@ func (ctl *Control) connectServer() (conn frpNet.Conn, err error) {
|
|||||||
|
|
||||||
// reader read all messages from frps and send to readCh
|
// reader read all messages from frps and send to readCh
|
||||||
func (ctl *Control) reader() {
|
func (ctl *Control) reader() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
defer ctl.readerShutdown.Done()
|
defer ctl.readerShutdown.Done()
|
||||||
@ -210,10 +223,10 @@ func (ctl *Control) reader() {
|
|||||||
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 {
|
||||||
ctl.Debug("read from control connection EOF")
|
xl.Debug("read from control connection EOF")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
ctl.Warn("read error: %v", err)
|
xl.Warn("read error: %v", err)
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -225,20 +238,21 @@ 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() {
|
||||||
|
xl := ctl.xl
|
||||||
defer ctl.writerShutdown.Done()
|
defer ctl.writerShutdown.Done()
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(ctl.clientCfg.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)
|
xl.Error("crypto new writer error: %v", err)
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
if m, ok := <-ctl.sendCh; !ok {
|
if m, ok := <-ctl.sendCh; !ok {
|
||||||
ctl.Info("control writer is closing")
|
xl.Info("control writer is closing")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if err := msg.WriteMsg(encWriter, m); err != nil {
|
if err := msg.WriteMsg(encWriter, m); err != nil {
|
||||||
ctl.Warn("write message to control connection error: %v", err)
|
xl.Warn("write message to control connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,10 +261,11 @@ func (ctl *Control) writer() {
|
|||||||
|
|
||||||
// msgHandler handles all channel events and do corresponding operations.
|
// msgHandler handles all channel events and do corresponding operations.
|
||||||
func (ctl *Control) msgHandler() {
|
func (ctl *Control) msgHandler() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
defer ctl.msgHandlerShutdown.Done()
|
defer ctl.msgHandlerShutdown.Done()
|
||||||
@ -266,11 +281,11 @@ func (ctl *Control) msgHandler() {
|
|||||||
select {
|
select {
|
||||||
case <-hbSend.C:
|
case <-hbSend.C:
|
||||||
// send heartbeat to server
|
// send heartbeat to server
|
||||||
ctl.Debug("send heartbeat to server")
|
xl.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(ctl.clientCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPong) > time.Duration(ctl.clientCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.Warn("heartbeat timeout")
|
xl.Warn("heartbeat timeout")
|
||||||
// let reader() stop
|
// let reader() stop
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
return
|
return
|
||||||
@ -287,7 +302,7 @@ func (ctl *Control) msgHandler() {
|
|||||||
ctl.HandleNewProxyResp(m)
|
ctl.HandleNewProxyResp(m)
|
||||||
case *msg.Pong:
|
case *msg.Pong:
|
||||||
ctl.lastPong = time.Now()
|
ctl.lastPong = time.Now()
|
||||||
ctl.Debug("receive heartbeat from server")
|
xl.Debug("receive heartbeat from server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -50,11 +50,11 @@ type HealthCheckMonitor struct {
|
|||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
||||||
l log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHealthCheckMonitor(checkType string, intervalS int, timeoutS int, maxFailedTimes int, addr string, url string,
|
func NewHealthCheckMonitor(ctx context.Context, checkType string,
|
||||||
|
intervalS int, timeoutS int, maxFailedTimes int,
|
||||||
|
addr string, url string,
|
||||||
statusNormalFn func(), statusFailedFn func()) *HealthCheckMonitor {
|
statusNormalFn func(), statusFailedFn func()) *HealthCheckMonitor {
|
||||||
|
|
||||||
if intervalS <= 0 {
|
if intervalS <= 0 {
|
||||||
@ -66,7 +66,7 @@ func NewHealthCheckMonitor(checkType string, intervalS int, timeoutS int, maxFai
|
|||||||
if maxFailedTimes <= 0 {
|
if maxFailedTimes <= 0 {
|
||||||
maxFailedTimes = 1
|
maxFailedTimes = 1
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
newctx, cancel := context.WithCancel(ctx)
|
||||||
return &HealthCheckMonitor{
|
return &HealthCheckMonitor{
|
||||||
checkType: checkType,
|
checkType: checkType,
|
||||||
interval: time.Duration(intervalS) * time.Second,
|
interval: time.Duration(intervalS) * time.Second,
|
||||||
@ -77,15 +77,11 @@ func NewHealthCheckMonitor(checkType string, intervalS int, timeoutS int, maxFai
|
|||||||
statusOK: false,
|
statusOK: false,
|
||||||
statusNormalFn: statusNormalFn,
|
statusNormalFn: statusNormalFn,
|
||||||
statusFailedFn: statusFailedFn,
|
statusFailedFn: statusFailedFn,
|
||||||
ctx: ctx,
|
ctx: newctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (monitor *HealthCheckMonitor) SetLogger(l log.Logger) {
|
|
||||||
monitor.l = l
|
|
||||||
}
|
|
||||||
|
|
||||||
func (monitor *HealthCheckMonitor) Start() {
|
func (monitor *HealthCheckMonitor) Start() {
|
||||||
go monitor.checkWorker()
|
go monitor.checkWorker()
|
||||||
}
|
}
|
||||||
@ -95,6 +91,7 @@ func (monitor *HealthCheckMonitor) Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (monitor *HealthCheckMonitor) checkWorker() {
|
func (monitor *HealthCheckMonitor) checkWorker() {
|
||||||
|
xl := xlog.FromContextSafe(monitor.ctx)
|
||||||
for {
|
for {
|
||||||
doCtx, cancel := context.WithDeadline(monitor.ctx, time.Now().Add(monitor.timeout))
|
doCtx, cancel := context.WithDeadline(monitor.ctx, time.Now().Add(monitor.timeout))
|
||||||
err := monitor.doCheck(doCtx)
|
err := monitor.doCheck(doCtx)
|
||||||
@ -109,25 +106,17 @@ func (monitor *HealthCheckMonitor) checkWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if monitor.l != nil {
|
xl.Trace("do one health check success")
|
||||||
monitor.l.Trace("do one health check success")
|
|
||||||
}
|
|
||||||
if !monitor.statusOK && monitor.statusNormalFn != nil {
|
if !monitor.statusOK && monitor.statusNormalFn != nil {
|
||||||
if monitor.l != nil {
|
xl.Info("health check status change to success")
|
||||||
monitor.l.Info("health check status change to success")
|
|
||||||
}
|
|
||||||
monitor.statusOK = true
|
monitor.statusOK = true
|
||||||
monitor.statusNormalFn()
|
monitor.statusNormalFn()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if monitor.l != nil {
|
xl.Warn("do one health check failed: %v", err)
|
||||||
monitor.l.Warn("do one health check failed: %v", err)
|
|
||||||
}
|
|
||||||
monitor.failedTimes++
|
monitor.failedTimes++
|
||||||
if monitor.statusOK && int(monitor.failedTimes) >= monitor.maxFailedTimes && monitor.statusFailedFn != nil {
|
if monitor.statusOK && int(monitor.failedTimes) >= monitor.maxFailedTimes && monitor.statusFailedFn != nil {
|
||||||
if monitor.l != nil {
|
xl.Warn("health check status change to failed")
|
||||||
monitor.l.Warn("health check status change to failed")
|
|
||||||
}
|
|
||||||
monitor.statusOK = false
|
monitor.statusOK = false
|
||||||
monitor.statusFailedFn()
|
monitor.statusFailedFn()
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -29,8 +30,8 @@ import (
|
|||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/models/plugin"
|
"github.com/fatedier/frp/models/plugin"
|
||||||
"github.com/fatedier/frp/models/proto/udp"
|
"github.com/fatedier/frp/models/proto/udp"
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
frpIo "github.com/fatedier/golib/io"
|
frpIo "github.com/fatedier/golib/io"
|
||||||
@ -44,17 +45,17 @@ type Proxy interface {
|
|||||||
Run() error
|
Run() error
|
||||||
|
|
||||||
// InWorkConn accept work connections registered to server.
|
// InWorkConn accept work connections registered to server.
|
||||||
InWorkConn(frpNet.Conn, *msg.StartWorkConn)
|
InWorkConn(net.Conn, *msg.StartWorkConn)
|
||||||
|
|
||||||
Close()
|
Close()
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
|
func NewProxy(ctx context.Context, pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serverUDPPort int) (pxy Proxy) {
|
||||||
baseProxy := BaseProxy{
|
baseProxy := BaseProxy{
|
||||||
Logger: log.NewPrefixLogger(pxyConf.GetBaseInfo().ProxyName),
|
|
||||||
clientCfg: clientCfg,
|
clientCfg: clientCfg,
|
||||||
serverUDPPort: serverUDPPort,
|
serverUDPPort: serverUDPPort,
|
||||||
|
xl: xlog.FromContextSafe(ctx),
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.TcpProxyConf:
|
case *config.TcpProxyConf:
|
||||||
@ -93,10 +94,12 @@ func NewProxy(pxyConf config.ProxyConf, clientCfg config.ClientCommonConf, serve
|
|||||||
|
|
||||||
type BaseProxy struct {
|
type BaseProxy struct {
|
||||||
closed bool
|
closed bool
|
||||||
mu sync.RWMutex
|
|
||||||
clientCfg config.ClientCommonConf
|
clientCfg config.ClientCommonConf
|
||||||
serverUDPPort int
|
serverUDPPort int
|
||||||
log.Logger
|
|
||||||
|
mu sync.RWMutex
|
||||||
|
xl *xlog.Logger
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCP
|
// TCP
|
||||||
@ -123,8 +126,8 @@ func (pxy *TcpProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *TcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *TcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(pxy.clientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +155,8 @@ func (pxy *HttpProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *HttpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(pxy.clientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,8 +184,8 @@ func (pxy *HttpsProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpsProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *HttpsProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(pxy.clientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,8 +213,8 @@ func (pxy *StcpProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *StcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *StcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf, conn,
|
||||||
[]byte(pxy.clientCfg.Token), m)
|
[]byte(pxy.clientCfg.Token), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,12 +242,13 @@ func (pxy *XtcpProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *XtcpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
|
xl := pxy.xl
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
var natHoleSidMsg msg.NatHoleSid
|
var natHoleSidMsg msg.NatHoleSid
|
||||||
err := msg.ReadMsgInto(conn, &natHoleSidMsg)
|
err := msg.ReadMsgInto(conn, &natHoleSidMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("xtcp read from workConn error: %v", err)
|
xl.Error("xtcp read from workConn error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,7 +263,7 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
|
|
||||||
err = msg.WriteMsg(clientConn, natHoleClientMsg)
|
err = msg.WriteMsg(clientConn, natHoleClientMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("send natHoleClientMsg to server error: %v", err)
|
xl.Error("send natHoleClientMsg to server error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,28 +274,28 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
buf := pool.GetBuf(1024)
|
buf := pool.GetBuf(1024)
|
||||||
n, err := clientConn.Read(buf)
|
n, err := clientConn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("get natHoleRespMsg error: %v", err)
|
xl.Error("get natHoleRespMsg error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = msg.ReadMsgInto(bytes.NewReader(buf[:n]), &natHoleRespMsg)
|
err = msg.ReadMsgInto(bytes.NewReader(buf[:n]), &natHoleRespMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("get natHoleRespMsg error: %v", err)
|
xl.Error("get natHoleRespMsg error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clientConn.SetReadDeadline(time.Time{})
|
clientConn.SetReadDeadline(time.Time{})
|
||||||
clientConn.Close()
|
clientConn.Close()
|
||||||
|
|
||||||
if natHoleRespMsg.Error != "" {
|
if natHoleRespMsg.Error != "" {
|
||||||
pxy.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
|
xl.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pxy.Trace("get natHoleRespMsg, sid [%s], client address [%s] visitor address [%s]", natHoleRespMsg.Sid, natHoleRespMsg.ClientAddr, natHoleRespMsg.VisitorAddr)
|
xl.Trace("get natHoleRespMsg, sid [%s], client address [%s] visitor address [%s]", natHoleRespMsg.Sid, natHoleRespMsg.ClientAddr, natHoleRespMsg.VisitorAddr)
|
||||||
|
|
||||||
// Send detect message
|
// Send detect message
|
||||||
array := strings.Split(natHoleRespMsg.VisitorAddr, ":")
|
array := strings.Split(natHoleRespMsg.VisitorAddr, ":")
|
||||||
if len(array) <= 1 {
|
if len(array) <= 1 {
|
||||||
pxy.Error("get NatHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
|
xl.Error("get NatHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
|
||||||
}
|
}
|
||||||
laddr, _ := net.ResolveUDPAddr("udp", clientConn.LocalAddr().String())
|
laddr, _ := net.ResolveUDPAddr("udp", clientConn.LocalAddr().String())
|
||||||
/*
|
/*
|
||||||
@ -301,18 +305,18 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
*/
|
*/
|
||||||
port, err := strconv.ParseInt(array[1], 10, 64)
|
port, err := strconv.ParseInt(array[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("get natHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
|
xl.Error("get natHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pxy.sendDetectMsg(array[0], int(port), laddr, []byte(natHoleRespMsg.Sid))
|
pxy.sendDetectMsg(array[0], int(port), laddr, []byte(natHoleRespMsg.Sid))
|
||||||
pxy.Trace("send all detect msg done")
|
xl.Trace("send all detect msg done")
|
||||||
|
|
||||||
msg.WriteMsg(conn, &msg.NatHoleClientDetectOK{})
|
msg.WriteMsg(conn, &msg.NatHoleClientDetectOK{})
|
||||||
|
|
||||||
// Listen for clientConn's address and wait for visitor connection
|
// Listen for clientConn's address and wait for visitor connection
|
||||||
lConn, err := net.ListenUDP("udp", laddr)
|
lConn, err := net.ListenUDP("udp", laddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("listen on visitorConn's local adress error: %v", err)
|
xl.Error("listen on visitorConn's local adress error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer lConn.Close()
|
defer lConn.Close()
|
||||||
@ -322,22 +326,22 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
var uAddr *net.UDPAddr
|
var uAddr *net.UDPAddr
|
||||||
n, uAddr, err = lConn.ReadFromUDP(sidBuf)
|
n, uAddr, err = lConn.ReadFromUDP(sidBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Warn("get sid from visitor error: %v", err)
|
xl.Warn("get sid from visitor error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lConn.SetReadDeadline(time.Time{})
|
lConn.SetReadDeadline(time.Time{})
|
||||||
if string(sidBuf[:n]) != natHoleRespMsg.Sid {
|
if string(sidBuf[:n]) != natHoleRespMsg.Sid {
|
||||||
pxy.Warn("incorrect sid from visitor")
|
xl.Warn("incorrect sid from visitor")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pool.PutBuf(sidBuf)
|
pool.PutBuf(sidBuf)
|
||||||
pxy.Info("nat hole connection make success, sid [%s]", natHoleRespMsg.Sid)
|
xl.Info("nat hole connection make success, sid [%s]", natHoleRespMsg.Sid)
|
||||||
|
|
||||||
lConn.WriteToUDP(sidBuf[:n], uAddr)
|
lConn.WriteToUDP(sidBuf[:n], uAddr)
|
||||||
|
|
||||||
kcpConn, err := frpNet.NewKcpConnFromUdp(lConn, false, natHoleRespMsg.VisitorAddr)
|
kcpConn, err := frpNet.NewKcpConnFromUdp(lConn, false, natHoleRespMsg.VisitorAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create kcp connection from udp connection error: %v", err)
|
xl.Error("create kcp connection from udp connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,18 +350,18 @@ func (pxy *XtcpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
fmuxCfg.LogOutput = ioutil.Discard
|
fmuxCfg.LogOutput = ioutil.Discard
|
||||||
sess, err := fmux.Server(kcpConn, fmuxCfg)
|
sess, err := fmux.Server(kcpConn, fmuxCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create yamux server from kcp connection error: %v", err)
|
xl.Error("create yamux server from kcp connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
muxConn, err := sess.Accept()
|
muxConn, err := sess.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("accept for yamux connection error: %v", err)
|
xl.Error("accept for yamux connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleTcpWorkConnection(&pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf,
|
HandleTcpWorkConnection(pxy.ctx, &pxy.cfg.LocalSvrConf, pxy.proxyPlugin, &pxy.cfg.BaseProxyConf,
|
||||||
frpNet.WrapConn(muxConn), []byte(pxy.cfg.Sk), m)
|
muxConn, []byte(pxy.cfg.Sk), m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *XtcpProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, content []byte) (err error) {
|
func (pxy *XtcpProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, content []byte) (err error) {
|
||||||
@ -390,7 +394,7 @@ type UdpProxy struct {
|
|||||||
|
|
||||||
// include msg.UdpPacket and msg.Ping
|
// include msg.UdpPacket and msg.Ping
|
||||||
sendCh chan msg.Message
|
sendCh chan msg.Message
|
||||||
workConn frpNet.Conn
|
workConn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *UdpProxy) Run() (err error) {
|
func (pxy *UdpProxy) Run() (err error) {
|
||||||
@ -419,8 +423,9 @@ func (pxy *UdpProxy) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pxy *UdpProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
|
||||||
pxy.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
|
xl := pxy.xl
|
||||||
|
xl.Info("incoming a new work connection for udp proxy, %s", conn.RemoteAddr().String())
|
||||||
// close resources releated with old workConn
|
// close resources releated with old workConn
|
||||||
pxy.Close()
|
pxy.Close()
|
||||||
|
|
||||||
@ -435,32 +440,32 @@ func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
for {
|
for {
|
||||||
var udpMsg msg.UdpPacket
|
var udpMsg msg.UdpPacket
|
||||||
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
|
if errRet := msg.ReadMsgInto(conn, &udpMsg); errRet != nil {
|
||||||
pxy.Warn("read from workConn for udp error: %v", errRet)
|
xl.Warn("read from workConn for udp error: %v", errRet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errRet := errors.PanicToError(func() {
|
if errRet := errors.PanicToError(func() {
|
||||||
pxy.Trace("get udp package from workConn: %s", udpMsg.Content)
|
xl.Trace("get udp package from workConn: %s", udpMsg.Content)
|
||||||
readCh <- &udpMsg
|
readCh <- &udpMsg
|
||||||
}); errRet != nil {
|
}); errRet != nil {
|
||||||
pxy.Info("reader goroutine for udp work connection closed: %v", errRet)
|
xl.Info("reader goroutine for udp work connection closed: %v", errRet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
|
workConnSenderFn := func(conn net.Conn, sendCh chan msg.Message) {
|
||||||
defer func() {
|
defer func() {
|
||||||
pxy.Info("writer goroutine for udp work connection closed")
|
xl.Info("writer goroutine for udp work connection closed")
|
||||||
}()
|
}()
|
||||||
var errRet error
|
var errRet error
|
||||||
for rawMsg := range sendCh {
|
for rawMsg := range sendCh {
|
||||||
switch m := rawMsg.(type) {
|
switch m := rawMsg.(type) {
|
||||||
case *msg.UdpPacket:
|
case *msg.UdpPacket:
|
||||||
pxy.Trace("send udp package to workConn: %s", m.Content)
|
xl.Trace("send udp package to workConn: %s", m.Content)
|
||||||
case *msg.Ping:
|
case *msg.Ping:
|
||||||
pxy.Trace("send ping message to udp workConn")
|
xl.Trace("send ping message to udp workConn")
|
||||||
}
|
}
|
||||||
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
|
if errRet = msg.WriteMsg(conn, rawMsg); errRet != nil {
|
||||||
pxy.Error("udp work write error: %v", errRet)
|
xl.Error("udp work write error: %v", errRet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,7 +477,7 @@ func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
if errRet = errors.PanicToError(func() {
|
if errRet = errors.PanicToError(func() {
|
||||||
sendCh <- &msg.Ping{}
|
sendCh <- &msg.Ping{}
|
||||||
}); errRet != nil {
|
}); errRet != nil {
|
||||||
pxy.Trace("heartbeat goroutine for udp work connection closed")
|
xl.Trace("heartbeat goroutine for udp work connection closed")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,20 +490,22 @@ func (pxy *UdpProxy) InWorkConn(conn frpNet.Conn, m *msg.StartWorkConn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Common handler for tcp work connections.
|
// Common handler for tcp work connections.
|
||||||
func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
|
func HandleTcpWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
|
||||||
baseInfo *config.BaseProxyConf, workConn frpNet.Conn, encKey []byte, m *msg.StartWorkConn) {
|
baseInfo *config.BaseProxyConf, workConn net.Conn, encKey []byte, m *msg.StartWorkConn) {
|
||||||
|
xl := xlog.FromContextSafe(ctx)
|
||||||
var (
|
var (
|
||||||
remote io.ReadWriteCloser
|
remote io.ReadWriteCloser
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
remote = workConn
|
remote = workConn
|
||||||
|
|
||||||
|
xl.Trace("handle tcp work connection, use_encryption: %t, use_compression: %t",
|
||||||
|
baseInfo.UseEncryption, baseInfo.UseCompression)
|
||||||
if baseInfo.UseEncryption {
|
if baseInfo.UseEncryption {
|
||||||
remote, err = frpIo.WithEncryption(remote, encKey)
|
remote, err = frpIo.WithEncryption(remote, encKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
workConn.Error("create encryption stream error: %v", err)
|
xl.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,19 +548,19 @@ func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.
|
|||||||
|
|
||||||
if proxyPlugin != nil {
|
if proxyPlugin != nil {
|
||||||
// if plugin is set, let plugin handle connections first
|
// if plugin is set, let plugin handle connections first
|
||||||
workConn.Debug("handle by plugin: %s", proxyPlugin.Name())
|
xl.Debug("handle by plugin: %s", proxyPlugin.Name())
|
||||||
proxyPlugin.Handle(remote, workConn, extraInfo)
|
proxyPlugin.Handle(remote, workConn, extraInfo)
|
||||||
workConn.Debug("handle by plugin finished")
|
xl.Debug("handle by plugin finished")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
localConn, err := frpNet.ConnectServer("tcp", fmt.Sprintf("%s:%d", localInfo.LocalIp, localInfo.LocalPort))
|
localConn, err := frpNet.ConnectServer("tcp", fmt.Sprintf("%s:%d", localInfo.LocalIp, localInfo.LocalPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
workConn.Error("connect to local service [%s:%d] error: %v", localInfo.LocalIp, localInfo.LocalPort, err)
|
xl.Error("connect to local service [%s:%d] error: %v", localInfo.LocalIp, localInfo.LocalPort, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
workConn.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
|
xl.Debug("join connections, localConn(l[%s] r[%s]) workConn(l[%s] r[%s])", localConn.LocalAddr().String(),
|
||||||
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||||
|
|
||||||
if len(extraInfo) > 0 {
|
if len(extraInfo) > 0 {
|
||||||
@ -561,6 +568,6 @@ func HandleTcpWorkConnection(localInfo *config.LocalSvrConf, proxyPlugin plugin.
|
|||||||
}
|
}
|
||||||
|
|
||||||
frpIo.Join(localConn, remote)
|
frpIo.Join(localConn, remote)
|
||||||
workConn.Debug("join connections closed")
|
xl.Debug("join connections closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client/event"
|
"github.com/fatedier/frp/client/event"
|
||||||
"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/xlog"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
)
|
)
|
||||||
@ -25,19 +26,17 @@ type ProxyManager struct {
|
|||||||
// The UDP port that the server is listening on
|
// The UDP port that the server is listening on
|
||||||
serverUDPPort int
|
serverUDPPort int
|
||||||
|
|
||||||
logPrefix string
|
ctx context.Context
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyManager(msgSendCh chan (msg.Message), logPrefix string, clientCfg config.ClientCommonConf, serverUDPPort int) *ProxyManager {
|
func NewProxyManager(ctx context.Context, msgSendCh chan (msg.Message), clientCfg config.ClientCommonConf, serverUDPPort int) *ProxyManager {
|
||||||
return &ProxyManager{
|
return &ProxyManager{
|
||||||
proxies: make(map[string]*ProxyWrapper),
|
|
||||||
sendCh: msgSendCh,
|
sendCh: msgSendCh,
|
||||||
|
proxies: make(map[string]*ProxyWrapper),
|
||||||
closed: false,
|
closed: false,
|
||||||
clientCfg: clientCfg,
|
clientCfg: clientCfg,
|
||||||
serverUDPPort: serverUDPPort,
|
serverUDPPort: serverUDPPort,
|
||||||
logPrefix: logPrefix,
|
ctx: ctx,
|
||||||
Logger: log.NewPrefixLogger(logPrefix),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ func (pm *ProxyManager) Close() {
|
|||||||
pm.proxies = make(map[string]*ProxyWrapper)
|
pm.proxies = make(map[string]*ProxyWrapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *ProxyManager) HandleWorkConn(name string, workConn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pm *ProxyManager) HandleWorkConn(name string, workConn net.Conn, m *msg.StartWorkConn) {
|
||||||
pm.mu.RLock()
|
pm.mu.RLock()
|
||||||
pw, ok := pm.proxies[name]
|
pw, ok := pm.proxies[name]
|
||||||
pm.mu.RUnlock()
|
pm.mu.RUnlock()
|
||||||
@ -104,6 +103,7 @@ func (pm *ProxyManager) GetAllProxyStatus() []*ProxyStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
|
func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
|
||||||
|
xl := xlog.FromContextSafe(pm.ctx)
|
||||||
pm.mu.Lock()
|
pm.mu.Lock()
|
||||||
defer pm.mu.Unlock()
|
defer pm.mu.Unlock()
|
||||||
|
|
||||||
@ -127,13 +127,13 @@ func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(delPxyNames) > 0 {
|
if len(delPxyNames) > 0 {
|
||||||
pm.Info("proxy removed: %v", delPxyNames)
|
xl.Info("proxy removed: %v", delPxyNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
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.clientCfg, pm.HandleEvent, pm.logPrefix, pm.serverUDPPort)
|
pxy := NewProxyWrapper(pm.ctx, cfg, pm.clientCfg, pm.HandleEvent, pm.serverUDPPort)
|
||||||
pm.proxies[name] = pxy
|
pm.proxies[name] = pxy
|
||||||
addPxyNames = append(addPxyNames, name)
|
addPxyNames = append(addPxyNames, name)
|
||||||
|
|
||||||
@ -141,6 +141,6 @@ func (pm *ProxyManager) Reload(pxyCfgs map[string]config.ProxyConf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(addPxyNames) > 0 {
|
if len(addPxyNames) > 0 {
|
||||||
pm.Info("proxy added: %v", addPxyNames)
|
xl.Info("proxy added: %v", addPxyNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@ -10,8 +12,7 @@ import (
|
|||||||
"github.com/fatedier/frp/client/health"
|
"github.com/fatedier/frp/client/health"
|
||||||
"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/xlog"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
)
|
)
|
||||||
@ -62,11 +63,13 @@ type ProxyWrapper struct {
|
|||||||
healthNotifyCh chan struct{}
|
healthNotifyCh chan struct{}
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
log.Logger
|
xl *xlog.Logger
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxyWrapper(cfg config.ProxyConf, clientCfg config.ClientCommonConf, eventHandler event.EventHandler, logPrefix string, serverUDPPort int) *ProxyWrapper {
|
func NewProxyWrapper(ctx context.Context, cfg config.ProxyConf, clientCfg config.ClientCommonConf, eventHandler event.EventHandler, serverUDPPort int) *ProxyWrapper {
|
||||||
baseInfo := cfg.GetBaseInfo()
|
baseInfo := cfg.GetBaseInfo()
|
||||||
|
xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(baseInfo.ProxyName)
|
||||||
pw := &ProxyWrapper{
|
pw := &ProxyWrapper{
|
||||||
ProxyStatus: ProxyStatus{
|
ProxyStatus: ProxyStatus{
|
||||||
Name: baseInfo.ProxyName,
|
Name: baseInfo.ProxyName,
|
||||||
@ -77,20 +80,19 @@ func NewProxyWrapper(cfg config.ProxyConf, clientCfg config.ClientCommonConf, ev
|
|||||||
closeCh: make(chan struct{}),
|
closeCh: make(chan struct{}),
|
||||||
healthNotifyCh: make(chan struct{}),
|
healthNotifyCh: make(chan struct{}),
|
||||||
handler: eventHandler,
|
handler: eventHandler,
|
||||||
Logger: log.NewPrefixLogger(logPrefix),
|
xl: xl,
|
||||||
|
ctx: xlog.NewContext(ctx, xl),
|
||||||
}
|
}
|
||||||
pw.AddLogPrefix(pw.Name)
|
|
||||||
|
|
||||||
if baseInfo.HealthCheckType != "" {
|
if baseInfo.HealthCheckType != "" {
|
||||||
pw.health = 1 // means failed
|
pw.health = 1 // means failed
|
||||||
pw.monitor = health.NewHealthCheckMonitor(baseInfo.HealthCheckType, baseInfo.HealthCheckIntervalS,
|
pw.monitor = health.NewHealthCheckMonitor(pw.ctx, baseInfo.HealthCheckType, baseInfo.HealthCheckIntervalS,
|
||||||
baseInfo.HealthCheckTimeoutS, baseInfo.HealthCheckMaxFailed, baseInfo.HealthCheckAddr,
|
baseInfo.HealthCheckTimeoutS, baseInfo.HealthCheckMaxFailed, baseInfo.HealthCheckAddr,
|
||||||
baseInfo.HealthCheckUrl, pw.statusNormalCallback, pw.statusFailedCallback)
|
baseInfo.HealthCheckUrl, pw.statusNormalCallback, pw.statusFailedCallback)
|
||||||
pw.monitor.SetLogger(pw.Logger)
|
xl.Trace("enable health check monitor")
|
||||||
pw.Trace("enable health check monitor")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pw.pxy = NewProxy(pw.Cfg, clientCfg, serverUDPPort)
|
pw.pxy = NewProxy(pw.ctx, pw.Cfg, clientCfg, serverUDPPort)
|
||||||
return pw
|
return pw
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +149,7 @@ func (pw *ProxyWrapper) Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pw *ProxyWrapper) checkWorker() {
|
func (pw *ProxyWrapper) checkWorker() {
|
||||||
|
xl := pw.xl
|
||||||
if pw.monitor != nil {
|
if pw.monitor != nil {
|
||||||
// let monitor do check request first
|
// let monitor do check request first
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
@ -161,7 +164,7 @@ func (pw *ProxyWrapper) checkWorker() {
|
|||||||
(pw.Status == ProxyStatusWaitStart && now.After(pw.lastSendStartMsg.Add(waitResponseTimeout))) ||
|
(pw.Status == ProxyStatusWaitStart && now.After(pw.lastSendStartMsg.Add(waitResponseTimeout))) ||
|
||||||
(pw.Status == ProxyStatusStartErr && now.After(pw.lastStartErr.Add(startErrTimeout))) {
|
(pw.Status == ProxyStatusStartErr && now.After(pw.lastStartErr.Add(startErrTimeout))) {
|
||||||
|
|
||||||
pw.Trace("change status from [%s] to [%s]", pw.Status, ProxyStatusWaitStart)
|
xl.Trace("change status from [%s] to [%s]", pw.Status, ProxyStatusWaitStart)
|
||||||
pw.Status = ProxyStatusWaitStart
|
pw.Status = ProxyStatusWaitStart
|
||||||
|
|
||||||
var newProxyMsg msg.NewProxy
|
var newProxyMsg msg.NewProxy
|
||||||
@ -180,7 +183,7 @@ func (pw *ProxyWrapper) checkWorker() {
|
|||||||
ProxyName: pw.Name,
|
ProxyName: pw.Name,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
pw.Trace("change status from [%s] to [%s]", pw.Status, ProxyStatusCheckFailed)
|
xl.Trace("change status from [%s] to [%s]", pw.Status, ProxyStatusCheckFailed)
|
||||||
pw.Status = ProxyStatusCheckFailed
|
pw.Status = ProxyStatusCheckFailed
|
||||||
}
|
}
|
||||||
pw.mu.Unlock()
|
pw.mu.Unlock()
|
||||||
@ -196,6 +199,7 @@ func (pw *ProxyWrapper) checkWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pw *ProxyWrapper) statusNormalCallback() {
|
func (pw *ProxyWrapper) statusNormalCallback() {
|
||||||
|
xl := pw.xl
|
||||||
atomic.StoreUint32(&pw.health, 0)
|
atomic.StoreUint32(&pw.health, 0)
|
||||||
errors.PanicToError(func() {
|
errors.PanicToError(func() {
|
||||||
select {
|
select {
|
||||||
@ -203,10 +207,11 @@ func (pw *ProxyWrapper) statusNormalCallback() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
pw.Info("health check success")
|
xl.Info("health check success")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *ProxyWrapper) statusFailedCallback() {
|
func (pw *ProxyWrapper) statusFailedCallback() {
|
||||||
|
xl := pw.xl
|
||||||
atomic.StoreUint32(&pw.health, 1)
|
atomic.StoreUint32(&pw.health, 1)
|
||||||
errors.PanicToError(func() {
|
errors.PanicToError(func() {
|
||||||
select {
|
select {
|
||||||
@ -214,15 +219,16 @@ func (pw *ProxyWrapper) statusFailedCallback() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
pw.Info("health check failed")
|
xl.Info("health check failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pw *ProxyWrapper) InWorkConn(workConn frpNet.Conn, m *msg.StartWorkConn) {
|
func (pw *ProxyWrapper) InWorkConn(workConn net.Conn, m *msg.StartWorkConn) {
|
||||||
|
xl := pw.xl
|
||||||
pw.mu.RLock()
|
pw.mu.RLock()
|
||||||
pxy := pw.pxy
|
pxy := pw.pxy
|
||||||
pw.mu.RUnlock()
|
pw.mu.RUnlock()
|
||||||
if pxy != nil {
|
if pxy != nil {
|
||||||
workConn.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
xl.Debug("start a new work connection, localAddr: %s remoteAddr: %s", workConn.LocalAddr().String(), workConn.RemoteAddr().String())
|
||||||
go pxy.InWorkConn(workConn, m)
|
go pxy.InWorkConn(workConn, m)
|
||||||
} else {
|
} else {
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -30,6 +32,7 @@ import (
|
|||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
"github.com/fatedier/frp/utils/version"
|
"github.com/fatedier/frp/utils/version"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
fmux "github.com/hashicorp/yamux"
|
fmux "github.com/hashicorp/yamux"
|
||||||
)
|
)
|
||||||
@ -55,19 +58,25 @@ type Service struct {
|
|||||||
// This is configured by the login response from frps
|
// This is configured by the login response from frps
|
||||||
serverUDPPort int
|
serverUDPPort int
|
||||||
|
|
||||||
exit uint32 // 0 means not exit
|
exit uint32 // 0 means not exit
|
||||||
closedCh chan int
|
|
||||||
|
// service context
|
||||||
|
ctx context.Context
|
||||||
|
// call cancel to stop service
|
||||||
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
func NewService(cfg config.ClientCommonConf, pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf, cfgFile string) (svr *Service, err error) {
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
svr = &Service{
|
svr = &Service{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
cfgFile: cfgFile,
|
cfgFile: cfgFile,
|
||||||
pxyCfgs: pxyCfgs,
|
pxyCfgs: pxyCfgs,
|
||||||
visitorCfgs: visitorCfgs,
|
visitorCfgs: visitorCfgs,
|
||||||
exit: 0,
|
exit: 0,
|
||||||
closedCh: make(chan int),
|
ctx: xlog.NewContext(ctx, xlog.New()),
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -79,11 +88,13 @@ func (svr *Service) GetController() *Control {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Service) Run() error {
|
func (svr *Service) Run() error {
|
||||||
// first login
|
xl := xlog.FromContextSafe(svr.ctx)
|
||||||
|
|
||||||
|
// login to frps
|
||||||
for {
|
for {
|
||||||
conn, session, err := svr.login()
|
conn, session, err := svr.login()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("login to server failed: %v", err)
|
xl.Warn("login to server failed: %v", err)
|
||||||
|
|
||||||
// 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
|
||||||
@ -94,7 +105,7 @@ func (svr *Service) Run() error {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// login success
|
// login success
|
||||||
ctl := NewControl(svr.runId, conn, session, svr.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
|
ctl := NewControl(svr.ctx, 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
|
||||||
@ -118,12 +129,12 @@ func (svr *Service) Run() error {
|
|||||||
}
|
}
|
||||||
log.Info("admin server listen on %s:%d", svr.cfg.AdminAddr, svr.cfg.AdminPort)
|
log.Info("admin server listen on %s:%d", svr.cfg.AdminAddr, svr.cfg.AdminPort)
|
||||||
}
|
}
|
||||||
|
<-svr.ctx.Done()
|
||||||
<-svr.closedCh
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Service) keepControllerWorking() {
|
func (svr *Service) keepControllerWorking() {
|
||||||
|
xl := xlog.FromContextSafe(svr.ctx)
|
||||||
maxDelayTime := 20 * time.Second
|
maxDelayTime := 20 * time.Second
|
||||||
delayTime := time.Second
|
delayTime := time.Second
|
||||||
|
|
||||||
@ -134,10 +145,10 @@ func (svr *Service) keepControllerWorking() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
log.Info("try to reconnect to server...")
|
xl.Info("try to reconnect to server...")
|
||||||
conn, session, err := svr.login()
|
conn, session, err := svr.login()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("reconnect to server error: %v", err)
|
xl.Warn("reconnect to server error: %v", err)
|
||||||
time.Sleep(delayTime)
|
time.Sleep(delayTime)
|
||||||
delayTime = delayTime * 2
|
delayTime = delayTime * 2
|
||||||
if delayTime > maxDelayTime {
|
if delayTime > maxDelayTime {
|
||||||
@ -148,7 +159,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.cfg, svr.pxyCfgs, svr.visitorCfgs, svr.serverUDPPort)
|
ctl := NewControl(svr.ctx, 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
|
||||||
@ -161,7 +172,8 @@ func (svr *Service) keepControllerWorking() {
|
|||||||
// login creates a connection to frps and registers it self as a client
|
// login creates a connection to frps and registers it self as a client
|
||||||
// conn: control connection
|
// conn: control connection
|
||||||
// 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 net.Conn, session *fmux.Session, err error) {
|
||||||
|
xl := xlog.FromContextSafe(svr.ctx)
|
||||||
var tlsConfig *tls.Config
|
var tlsConfig *tls.Config
|
||||||
if svr.cfg.TLSEnable {
|
if svr.cfg.TLSEnable {
|
||||||
tlsConfig = &tls.Config{
|
tlsConfig = &tls.Config{
|
||||||
@ -197,7 +209,7 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
|
|||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn = frpNet.WrapConn(stream)
|
conn = stream
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
@ -225,13 +237,16 @@ func (svr *Service) login() (conn frpNet.Conn, session *fmux.Session, err error)
|
|||||||
|
|
||||||
if loginRespMsg.Error != "" {
|
if loginRespMsg.Error != "" {
|
||||||
err = fmt.Errorf("%s", loginRespMsg.Error)
|
err = fmt.Errorf("%s", loginRespMsg.Error)
|
||||||
log.Error("%s", loginRespMsg.Error)
|
xl.Error("%s", loginRespMsg.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
svr.runId = loginRespMsg.RunId
|
svr.runId = loginRespMsg.RunId
|
||||||
|
xl.ResetPrefixes()
|
||||||
|
xl.AppendPrefix(svr.runId)
|
||||||
|
|
||||||
svr.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)
|
xl.Info("login to server success, get run id [%s], server udp port [%d]", loginRespMsg.RunId, loginRespMsg.ServerUdpPort)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,5 +262,5 @@ func (svr *Service) ReloadConf(pxyCfgs map[string]config.ProxyConf, visitorCfgs
|
|||||||
func (svr *Service) Close() {
|
func (svr *Service) Close() {
|
||||||
atomic.StoreUint32(&svr.exit, 1)
|
atomic.StoreUint32(&svr.exit, 1)
|
||||||
svr.ctl.Close()
|
svr.ctl.Close()
|
||||||
close(svr.closedCh)
|
svr.cancel()
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -25,9 +26,9 @@ import (
|
|||||||
|
|
||||||
"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"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
frpIo "github.com/fatedier/golib/io"
|
frpIo "github.com/fatedier/golib/io"
|
||||||
"github.com/fatedier/golib/pool"
|
"github.com/fatedier/golib/pool"
|
||||||
@ -38,13 +39,13 @@ import (
|
|||||||
type Visitor interface {
|
type Visitor interface {
|
||||||
Run() error
|
Run() error
|
||||||
Close()
|
Close()
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisitor(ctl *Control, cfg config.VisitorConf) (visitor Visitor) {
|
func NewVisitor(ctx context.Context, ctl *Control, cfg config.VisitorConf) (visitor Visitor) {
|
||||||
|
xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(cfg.GetBaseInfo().ProxyName)
|
||||||
baseVisitor := BaseVisitor{
|
baseVisitor := BaseVisitor{
|
||||||
ctl: ctl,
|
ctl: ctl,
|
||||||
Logger: log.NewPrefixLogger(cfg.GetBaseInfo().ProxyName),
|
ctx: xlog.NewContext(ctx, xl),
|
||||||
}
|
}
|
||||||
switch cfg := cfg.(type) {
|
switch cfg := cfg.(type) {
|
||||||
case *config.StcpVisitorConf:
|
case *config.StcpVisitorConf:
|
||||||
@ -63,10 +64,11 @@ func NewVisitor(ctl *Control, cfg config.VisitorConf) (visitor Visitor) {
|
|||||||
|
|
||||||
type BaseVisitor struct {
|
type BaseVisitor struct {
|
||||||
ctl *Control
|
ctl *Control
|
||||||
l frpNet.Listener
|
l net.Listener
|
||||||
closed bool
|
closed bool
|
||||||
mu sync.RWMutex
|
|
||||||
log.Logger
|
mu sync.RWMutex
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
type StcpVisitor struct {
|
type StcpVisitor struct {
|
||||||
@ -76,7 +78,7 @@ type StcpVisitor struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sv *StcpVisitor) Run() (err error) {
|
func (sv *StcpVisitor) Run() (err error) {
|
||||||
sv.l, err = frpNet.ListenTcp(sv.cfg.BindAddr, sv.cfg.BindPort)
|
sv.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sv.cfg.BindAddr, sv.cfg.BindPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -90,10 +92,11 @@ func (sv *StcpVisitor) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sv *StcpVisitor) worker() {
|
func (sv *StcpVisitor) worker() {
|
||||||
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
for {
|
for {
|
||||||
conn, err := sv.l.Accept()
|
conn, err := sv.l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("stcp local listener closed")
|
xl.Warn("stcp local listener closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,10 +104,11 @@ func (sv *StcpVisitor) worker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sv *StcpVisitor) handleConn(userConn frpNet.Conn) {
|
func (sv *StcpVisitor) handleConn(userConn net.Conn) {
|
||||||
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
sv.Debug("get a new stcp user connection")
|
xl.Debug("get a new stcp user connection")
|
||||||
visitorConn, err := sv.ctl.connectServer()
|
visitorConn, err := sv.ctl.connectServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -121,7 +125,7 @@ func (sv *StcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
}
|
}
|
||||||
err = msg.WriteMsg(visitorConn, newVisitorConnMsg)
|
err = msg.WriteMsg(visitorConn, newVisitorConnMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("send newVisitorConnMsg to server error: %v", err)
|
xl.Warn("send newVisitorConnMsg to server error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,13 +133,13 @@ func (sv *StcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
|
||||||
err = msg.ReadMsgInto(visitorConn, &newVisitorConnRespMsg)
|
err = msg.ReadMsgInto(visitorConn, &newVisitorConnRespMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("get newVisitorConnRespMsg error: %v", err)
|
xl.Warn("get newVisitorConnRespMsg error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
visitorConn.SetReadDeadline(time.Time{})
|
visitorConn.SetReadDeadline(time.Time{})
|
||||||
|
|
||||||
if newVisitorConnRespMsg.Error != "" {
|
if newVisitorConnRespMsg.Error != "" {
|
||||||
sv.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
|
xl.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +148,7 @@ func (sv *StcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
if sv.cfg.UseEncryption {
|
if sv.cfg.UseEncryption {
|
||||||
remote, err = frpIo.WithEncryption(remote, []byte(sv.cfg.Sk))
|
remote, err = frpIo.WithEncryption(remote, []byte(sv.cfg.Sk))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("create encryption stream error: %v", err)
|
xl.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +167,7 @@ type XtcpVisitor struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sv *XtcpVisitor) Run() (err error) {
|
func (sv *XtcpVisitor) Run() (err error) {
|
||||||
sv.l, err = frpNet.ListenTcp(sv.cfg.BindAddr, sv.cfg.BindPort)
|
sv.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", sv.cfg.BindAddr, sv.cfg.BindPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -177,10 +181,11 @@ func (sv *XtcpVisitor) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sv *XtcpVisitor) worker() {
|
func (sv *XtcpVisitor) worker() {
|
||||||
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
for {
|
for {
|
||||||
conn, err := sv.l.Accept()
|
conn, err := sv.l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("xtcp local listener closed")
|
xl.Warn("xtcp local listener closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,25 +193,26 @@ func (sv *XtcpVisitor) worker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
func (sv *XtcpVisitor) handleConn(userConn net.Conn) {
|
||||||
|
xl := xlog.FromContextSafe(sv.ctx)
|
||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
sv.Debug("get a new xtcp user connection")
|
xl.Debug("get a new xtcp user connection")
|
||||||
if sv.ctl.serverUDPPort == 0 {
|
if sv.ctl.serverUDPPort == 0 {
|
||||||
sv.Error("xtcp is not supported by server")
|
xl.Error("xtcp is not supported by server")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
raddr, err := net.ResolveUDPAddr("udp",
|
raddr, err := net.ResolveUDPAddr("udp",
|
||||||
fmt.Sprintf("%s:%d", sv.ctl.clientCfg.ServerAddr, sv.ctl.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")
|
xl.Error("resolve server UDP addr error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
visitorConn, err := net.DialUDP("udp", nil, raddr)
|
visitorConn, err := net.DialUDP("udp", nil, raddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("dial server udp addr error: %v", err)
|
xl.Warn("dial server udp addr error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer visitorConn.Close()
|
defer visitorConn.Close()
|
||||||
@ -219,7 +225,7 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
}
|
}
|
||||||
err = msg.WriteMsg(visitorConn, natHoleVisitorMsg)
|
err = msg.WriteMsg(visitorConn, natHoleVisitorMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("send natHoleVisitorMsg to server error: %v", err)
|
xl.Warn("send natHoleVisitorMsg to server error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,24 +235,24 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
buf := pool.GetBuf(1024)
|
buf := pool.GetBuf(1024)
|
||||||
n, err := visitorConn.Read(buf)
|
n, err := visitorConn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("get natHoleRespMsg error: %v", err)
|
xl.Warn("get natHoleRespMsg error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = msg.ReadMsgInto(bytes.NewReader(buf[:n]), &natHoleRespMsg)
|
err = msg.ReadMsgInto(bytes.NewReader(buf[:n]), &natHoleRespMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("get natHoleRespMsg error: %v", err)
|
xl.Warn("get natHoleRespMsg error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
visitorConn.SetReadDeadline(time.Time{})
|
visitorConn.SetReadDeadline(time.Time{})
|
||||||
pool.PutBuf(buf)
|
pool.PutBuf(buf)
|
||||||
|
|
||||||
if natHoleRespMsg.Error != "" {
|
if natHoleRespMsg.Error != "" {
|
||||||
sv.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
|
xl.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sv.Trace("get natHoleRespMsg, sid [%s], client address [%s], visitor address [%s]", natHoleRespMsg.Sid, natHoleRespMsg.ClientAddr, natHoleRespMsg.VisitorAddr)
|
xl.Trace("get natHoleRespMsg, sid [%s], client address [%s], visitor address [%s]", natHoleRespMsg.Sid, natHoleRespMsg.ClientAddr, natHoleRespMsg.VisitorAddr)
|
||||||
|
|
||||||
// Close visitorConn, so we can use it's local address.
|
// Close visitorConn, so we can use it's local address.
|
||||||
visitorConn.Close()
|
visitorConn.Close()
|
||||||
@ -255,12 +261,12 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
laddr, _ := net.ResolveUDPAddr("udp", visitorConn.LocalAddr().String())
|
laddr, _ := net.ResolveUDPAddr("udp", visitorConn.LocalAddr().String())
|
||||||
daddr, err := net.ResolveUDPAddr("udp", natHoleRespMsg.ClientAddr)
|
daddr, err := net.ResolveUDPAddr("udp", natHoleRespMsg.ClientAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("resolve client udp address error: %v", err)
|
xl.Error("resolve client udp address error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lConn, err := net.DialUDP("udp", laddr, daddr)
|
lConn, err := net.DialUDP("udp", laddr, daddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("dial client udp address error: %v", err)
|
xl.Error("dial client udp address error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer lConn.Close()
|
defer lConn.Close()
|
||||||
@ -272,23 +278,23 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
|
lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
|
||||||
n, err = lConn.Read(sidBuf)
|
n, err = lConn.Read(sidBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Warn("get sid from client error: %v", err)
|
xl.Warn("get sid from client error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
lConn.SetReadDeadline(time.Time{})
|
lConn.SetReadDeadline(time.Time{})
|
||||||
if string(sidBuf[:n]) != natHoleRespMsg.Sid {
|
if string(sidBuf[:n]) != natHoleRespMsg.Sid {
|
||||||
sv.Warn("incorrect sid from client")
|
xl.Warn("incorrect sid from client")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pool.PutBuf(sidBuf)
|
pool.PutBuf(sidBuf)
|
||||||
|
|
||||||
sv.Info("nat hole connection make success, sid [%s]", natHoleRespMsg.Sid)
|
xl.Info("nat hole connection make success, sid [%s]", natHoleRespMsg.Sid)
|
||||||
|
|
||||||
// wrap kcp connection
|
// wrap kcp connection
|
||||||
var remote io.ReadWriteCloser
|
var remote io.ReadWriteCloser
|
||||||
remote, err = frpNet.NewKcpConnFromUdp(lConn, true, natHoleRespMsg.ClientAddr)
|
remote, err = frpNet.NewKcpConnFromUdp(lConn, true, natHoleRespMsg.ClientAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("create kcp connection from udp connection error: %v", err)
|
xl.Error("create kcp connection from udp connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,13 +303,13 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
fmuxCfg.LogOutput = ioutil.Discard
|
fmuxCfg.LogOutput = ioutil.Discard
|
||||||
sess, err := fmux.Client(remote, fmuxCfg)
|
sess, err := fmux.Client(remote, fmuxCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("create yamux session error: %v", err)
|
xl.Error("create yamux session error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
muxConn, err := sess.Open()
|
muxConn, err := sess.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("open yamux stream error: %v", err)
|
xl.Error("open yamux stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +317,7 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
if sv.cfg.UseEncryption {
|
if sv.cfg.UseEncryption {
|
||||||
muxConnRWCloser, err = frpIo.WithEncryption(muxConnRWCloser, []byte(sv.cfg.Sk))
|
muxConnRWCloser, err = frpIo.WithEncryption(muxConnRWCloser, []byte(sv.cfg.Sk))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sv.Error("create encryption stream error: %v", err)
|
xl.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,5 +326,5 @@ func (sv *XtcpVisitor) handleConn(userConn frpNet.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
frpIo.Join(userConn, muxConnRWCloser)
|
frpIo.Join(userConn, muxConnRWCloser)
|
||||||
sv.Debug("join connections closed")
|
xl.Debug("join connections closed")
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VisitorManager struct {
|
type VisitorManager struct {
|
||||||
@ -30,26 +31,29 @@ type VisitorManager struct {
|
|||||||
|
|
||||||
checkInterval time.Duration
|
checkInterval time.Duration
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVisitorManager(ctl *Control) *VisitorManager {
|
func NewVisitorManager(ctx context.Context, ctl *Control) *VisitorManager {
|
||||||
return &VisitorManager{
|
return &VisitorManager{
|
||||||
ctl: ctl,
|
ctl: ctl,
|
||||||
cfgs: make(map[string]config.VisitorConf),
|
cfgs: make(map[string]config.VisitorConf),
|
||||||
visitors: make(map[string]Visitor),
|
visitors: make(map[string]Visitor),
|
||||||
checkInterval: 10 * time.Second,
|
checkInterval: 10 * time.Second,
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VisitorManager) Run() {
|
func (vm *VisitorManager) Run() {
|
||||||
|
xl := xlog.FromContextSafe(vm.ctx)
|
||||||
for {
|
for {
|
||||||
time.Sleep(vm.checkInterval)
|
time.Sleep(vm.checkInterval)
|
||||||
vm.mu.Lock()
|
vm.mu.Lock()
|
||||||
for _, cfg := range vm.cfgs {
|
for _, cfg := range vm.cfgs {
|
||||||
name := cfg.GetBaseInfo().ProxyName
|
name := cfg.GetBaseInfo().ProxyName
|
||||||
if _, exist := vm.visitors[name]; !exist {
|
if _, exist := vm.visitors[name]; !exist {
|
||||||
log.Info("try to start visitor [%s]", name)
|
xl.Info("try to start visitor [%s]", name)
|
||||||
vm.startVisitor(cfg)
|
vm.startVisitor(cfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,19 +63,21 @@ func (vm *VisitorManager) Run() {
|
|||||||
|
|
||||||
// Hold lock before calling this function.
|
// Hold lock before calling this function.
|
||||||
func (vm *VisitorManager) startVisitor(cfg config.VisitorConf) (err error) {
|
func (vm *VisitorManager) startVisitor(cfg config.VisitorConf) (err error) {
|
||||||
|
xl := xlog.FromContextSafe(vm.ctx)
|
||||||
name := cfg.GetBaseInfo().ProxyName
|
name := cfg.GetBaseInfo().ProxyName
|
||||||
visitor := NewVisitor(vm.ctl, cfg)
|
visitor := NewVisitor(vm.ctx, vm.ctl, cfg)
|
||||||
err = visitor.Run()
|
err = visitor.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
visitor.Warn("start error: %v", err)
|
xl.Warn("start error: %v", err)
|
||||||
} else {
|
} else {
|
||||||
vm.visitors[name] = visitor
|
vm.visitors[name] = visitor
|
||||||
visitor.Info("start visitor success")
|
xl.Info("start visitor success")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
|
func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
|
||||||
|
xl := xlog.FromContextSafe(vm.ctx)
|
||||||
vm.mu.Lock()
|
vm.mu.Lock()
|
||||||
defer vm.mu.Unlock()
|
defer vm.mu.Unlock()
|
||||||
|
|
||||||
@ -97,7 +103,7 @@ func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(delNames) > 0 {
|
if len(delNames) > 0 {
|
||||||
log.Info("visitor removed: %v", delNames)
|
xl.Info("visitor removed: %v", delNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
addNames := make([]string, 0)
|
addNames := make([]string, 0)
|
||||||
@ -109,7 +115,7 @@ func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(addNames) > 0 {
|
if len(addNames) > 0 {
|
||||||
log.Info("visitor added: %v", addNames)
|
xl.Info("visitor added: %v", addNames)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ func runServer(cfg config.ServerCommonConf) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("Start frps success")
|
log.Info("start frps success")
|
||||||
svr.Run()
|
svr.Run()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
14
go.sum
14
go.sum
@ -1,14 +1,10 @@
|
|||||||
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/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
github.com/fatedier/beego v0.0.0-20171024143340-6c6a4f5bd5eb/go.mod h1:wx3gB6dbIfBRcucp94PI9Bt3I0F2c/MyNEWuhzpWiwk=
|
||||||
github.com/fatedier/golib v0.0.0-20181107124048-ff8cd814b049 h1:teH578mf2ii42NHhIp3PhgvjU5bv+NFMq9fSQR8NaG8=
|
github.com/fatedier/golib v0.0.0-20181107124048-ff8cd814b049 h1:teH578mf2ii42NHhIp3PhgvjU5bv+NFMq9fSQR8NaG8=
|
||||||
github.com/fatedier/golib v0.0.0-20181107124048-ff8cd814b049/go.mod h1:DqIrnl0rp3Zybg9zbJmozTy1n8fYJoX+QoAj9slIkKM=
|
github.com/fatedier/golib v0.0.0-20181107124048-ff8cd814b049/go.mod h1:DqIrnl0rp3Zybg9zbJmozTy1n8fYJoX+QoAj9slIkKM=
|
||||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
|
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1:ssXat9YXFvigNge/IkkZvFMn8yeYKFX+uI6wn2mLJ74=
|
||||||
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
|
github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s=
|
||||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049 h1:K9KHZbXKpGydfDN0aZrsoHpLJlZsBrGMFWbgLDGnPZk=
|
|
||||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
@ -26,28 +22,18 @@ github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/
|
|||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc h1:lNOt1SMsgHXTdpuGw+RpnJtzUcCb/oRKZP65pBy9pr8=
|
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc h1:lNOt1SMsgHXTdpuGw+RpnJtzUcCb/oRKZP65pBy9pr8=
|
||||||
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/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/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
|
github.com/rakyll/statik v0.1.1/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
|
||||||
github.com/rodaine/table v1.0.0 h1:UaCJG5Axc/cNXVGXqnCrffm1KxP0OfYLe1HuJLf5sFY=
|
|
||||||
github.com/rodaine/table v1.0.0/go.mod h1:YAUzwPOji0DUJNEvggdxyQcUAl4g3hDRcFlyjnnR51I=
|
github.com/rodaine/table v1.0.0/go.mod h1:YAUzwPOji0DUJNEvggdxyQcUAl4g3hDRcFlyjnnR51I=
|
||||||
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
|
||||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047 h1:K+jtWCOuZgCra7eXZ/VWn2FbJmrA/D058mTXhh2rq+8=
|
|
||||||
github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
github.com/templexxx/cpufeat v0.0.0-20170927014610-3794dfbfb047/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
|
||||||
github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554 h1:pexgSe+JCFuxG+uoMZLO+ce8KHtdHGhst4cs6rw3gmk=
|
|
||||||
github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
github.com/templexxx/xor v0.0.0-20170926022130-0af8e873c554/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
|
||||||
github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8 h1:6CNSDqI1wiE+JqyOy5Qt/yo/DoNI2/QmmOZeiCid2Nw=
|
|
||||||
github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
|
github.com/tjfoc/gmsm v0.0.0-20171124023159-98aa888b79d8/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
|
||||||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7tbLt/I/gQuP559o/0FrAkHKlQM/Ks=
|
|
||||||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
|
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||||
|
@ -64,7 +64,7 @@ func (hp *HttpProxy) Name() string {
|
|||||||
return PluginHttpProxy
|
return PluginHttpProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hp *HttpProxy) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte) {
|
func (hp *HttpProxy) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
|
||||||
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
||||||
|
|
||||||
sc, rd := gnet.NewSharedConn(wrapConn)
|
sc, rd := gnet.NewSharedConn(wrapConn)
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"strings"
|
"strings"
|
||||||
@ -115,7 +116,7 @@ func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) {
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte) {
|
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
|
||||||
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
||||||
p.l.PutConn(wrapConn)
|
p.l.PutConn(wrapConn)
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,7 +44,9 @@ func Create(name string, params map[string]string) (p Plugin, err error) {
|
|||||||
|
|
||||||
type Plugin interface {
|
type Plugin interface {
|
||||||
Name() string
|
Name() string
|
||||||
Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte)
|
|
||||||
|
// extraBufToLocal will send to local connection first, then join conn with local connection
|
||||||
|
Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte)
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ func NewSocks5Plugin(params map[string]string) (p Plugin, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sp *Socks5Plugin) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte) {
|
func (sp *Socks5Plugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
||||||
sp.Server.ServeConn(wrapConn)
|
sp.Server.ServeConn(wrapConn)
|
||||||
|
@ -16,6 +16,7 @@ package plugin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
@ -72,7 +73,7 @@ func NewStaticFilePlugin(params map[string]string) (Plugin, error) {
|
|||||||
return sp, nil
|
return sp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte) {
|
func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
|
||||||
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
|
||||||
sp.l.PutConn(wrapConn)
|
sp.l.PutConn(wrapConn)
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
frpIo "github.com/fatedier/golib/io"
|
frpIo "github.com/fatedier/golib/io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ func NewUnixDomainSocketPlugin(params map[string]string) (p Plugin, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uds *UnixDomainSocketPlugin) Handle(conn io.ReadWriteCloser, realConn frpNet.Conn, extraBufToLocal []byte) {
|
func (uds *UnixDomainSocketPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
|
||||||
localConn, err := net.DialUnix("unix", nil, uds.UnixAddr)
|
localConn, err := net.DialUnix("unix", nil, uds.UnixAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -15,8 +15,10 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -28,8 +30,8 @@ import (
|
|||||||
"github.com/fatedier/frp/server/controller"
|
"github.com/fatedier/frp/server/controller"
|
||||||
"github.com/fatedier/frp/server/proxy"
|
"github.com/fatedier/frp/server/proxy"
|
||||||
"github.com/fatedier/frp/server/stats"
|
"github.com/fatedier/frp/server/stats"
|
||||||
"github.com/fatedier/frp/utils/net"
|
|
||||||
"github.com/fatedier/frp/utils/version"
|
"github.com/fatedier/frp/utils/version"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
"github.com/fatedier/golib/control/shutdown"
|
"github.com/fatedier/golib/control/shutdown"
|
||||||
"github.com/fatedier/golib/crypto"
|
"github.com/fatedier/golib/crypto"
|
||||||
@ -131,9 +133,12 @@ type Control struct {
|
|||||||
|
|
||||||
// Server configuration information
|
// Server configuration information
|
||||||
serverCfg config.ServerCommonConf
|
serverCfg config.ServerCommonConf
|
||||||
|
|
||||||
|
xl *xlog.Logger
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManager,
|
func NewControl(ctx context.Context, rc *controller.ResourceController, pxyManager *proxy.ProxyManager,
|
||||||
statsCollector stats.Collector, ctlConn net.Conn, loginMsg *msg.Login,
|
statsCollector stats.Collector, ctlConn net.Conn, loginMsg *msg.Login,
|
||||||
serverCfg config.ServerCommonConf) *Control {
|
serverCfg config.ServerCommonConf) *Control {
|
||||||
|
|
||||||
@ -161,6 +166,8 @@ func NewControl(rc *controller.ResourceController, pxyManager *proxy.ProxyManage
|
|||||||
managerShutdown: shutdown.New(),
|
managerShutdown: shutdown.New(),
|
||||||
allShutdown: shutdown.New(),
|
allShutdown: shutdown.New(),
|
||||||
serverCfg: serverCfg,
|
serverCfg: serverCfg,
|
||||||
|
xl: xlog.FromContextSafe(ctx),
|
||||||
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,18 +192,19 @@ func (ctl *Control) Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) RegisterWorkConn(conn net.Conn) {
|
func (ctl *Control) RegisterWorkConn(conn net.Conn) {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case ctl.workConnCh <- conn:
|
case ctl.workConnCh <- conn:
|
||||||
ctl.conn.Debug("new work connection registered")
|
xl.Debug("new work connection registered")
|
||||||
default:
|
default:
|
||||||
ctl.conn.Debug("work connection pool is full, discarding")
|
xl.Debug("work connection pool is full, discarding")
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -206,10 +214,11 @@ func (ctl *Control) RegisterWorkConn(conn net.Conn) {
|
|||||||
// and wait until it is available.
|
// and wait until it is available.
|
||||||
// return an error if wait timeout
|
// return an error if wait timeout
|
||||||
func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -221,14 +230,14 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
|||||||
err = frpErr.ErrCtlClosed
|
err = frpErr.ErrCtlClosed
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctl.conn.Debug("get work connection from pool")
|
xl.Debug("get work connection from pool")
|
||||||
default:
|
default:
|
||||||
// no work connections available in the poll, send message to frpc to get more
|
// no work connections available in the poll, send message to frpc to get more
|
||||||
err = errors.PanicToError(func() {
|
err = errors.PanicToError(func() {
|
||||||
ctl.sendCh <- &msg.ReqWorkConn{}
|
ctl.sendCh <- &msg.ReqWorkConn{}
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctl.conn.Error("%v", err)
|
xl.Error("%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,13 +245,13 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
|||||||
case workConn, ok = <-ctl.workConnCh:
|
case workConn, ok = <-ctl.workConnCh:
|
||||||
if !ok {
|
if !ok {
|
||||||
err = frpErr.ErrCtlClosed
|
err = frpErr.ErrCtlClosed
|
||||||
ctl.conn.Warn("no work connections avaiable, %v", err)
|
xl.Warn("no work connections avaiable, %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-time.After(time.Duration(ctl.serverCfg.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)
|
xl.Warn("%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,16 +264,18 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) Replaced(newCtl *Control) {
|
func (ctl *Control) Replaced(newCtl *Control) {
|
||||||
ctl.conn.Info("Replaced by client [%s]", newCtl.runId)
|
xl := ctl.xl
|
||||||
|
xl.Info("Replaced by client [%s]", newCtl.runId)
|
||||||
ctl.runId = ""
|
ctl.runId = ""
|
||||||
ctl.allShutdown.Start()
|
ctl.allShutdown.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) writer() {
|
func (ctl *Control) writer() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -273,17 +284,17 @@ func (ctl *Control) writer() {
|
|||||||
|
|
||||||
encWriter, err := crypto.NewWriter(ctl.conn, []byte(ctl.serverCfg.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)
|
xl.Error("crypto new writer error: %v", err)
|
||||||
ctl.allShutdown.Start()
|
ctl.allShutdown.Start()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
if m, ok := <-ctl.sendCh; !ok {
|
if m, ok := <-ctl.sendCh; !ok {
|
||||||
ctl.conn.Info("control writer is closing")
|
xl.Info("control writer is closing")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if err := msg.WriteMsg(encWriter, m); err != nil {
|
if err := msg.WriteMsg(encWriter, m); err != nil {
|
||||||
ctl.conn.Warn("write message to control connection error: %v", err)
|
xl.Warn("write message to control connection error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,10 +302,11 @@ func (ctl *Control) writer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) reader() {
|
func (ctl *Control) reader() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -305,10 +317,10 @@ func (ctl *Control) reader() {
|
|||||||
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 {
|
||||||
ctl.conn.Debug("control connection closed")
|
xl.Debug("control connection closed")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
ctl.conn.Warn("read error: %v", err)
|
xl.Warn("read error: %v", err)
|
||||||
ctl.conn.Close()
|
ctl.conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -319,10 +331,11 @@ func (ctl *Control) reader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) stoper() {
|
func (ctl *Control) stoper() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -355,7 +368,7 @@ func (ctl *Control) stoper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctl.allShutdown.Done()
|
ctl.allShutdown.Done()
|
||||||
ctl.conn.Info("client exit success")
|
xl.Info("client exit success")
|
||||||
|
|
||||||
ctl.statsCollector.Mark(stats.TypeCloseClient, &stats.CloseClientPayload{})
|
ctl.statsCollector.Mark(stats.TypeCloseClient, &stats.CloseClientPayload{})
|
||||||
}
|
}
|
||||||
@ -366,10 +379,11 @@ func (ctl *Control) WaitClosed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctl *Control) manager() {
|
func (ctl *Control) manager() {
|
||||||
|
xl := ctl.xl
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
ctl.conn.Error("panic error: %v", err)
|
xl.Error("panic error: %v", err)
|
||||||
ctl.conn.Error(string(debug.Stack()))
|
xl.Error(string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -383,7 +397,7 @@ func (ctl *Control) manager() {
|
|||||||
select {
|
select {
|
||||||
case <-heartbeat.C:
|
case <-heartbeat.C:
|
||||||
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartBeatTimeout)*time.Second {
|
if time.Since(ctl.lastPing) > time.Duration(ctl.serverCfg.HeartBeatTimeout)*time.Second {
|
||||||
ctl.conn.Warn("heartbeat timeout")
|
xl.Warn("heartbeat timeout")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case rawMsg, ok := <-ctl.readCh:
|
case rawMsg, ok := <-ctl.readCh:
|
||||||
@ -400,10 +414,10 @@ func (ctl *Control) manager() {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.Error = err.Error()
|
resp.Error = err.Error()
|
||||||
ctl.conn.Warn("new proxy [%s] error: %v", m.ProxyName, err)
|
xl.Warn("new proxy [%s] error: %v", m.ProxyName, err)
|
||||||
} else {
|
} else {
|
||||||
resp.RemoteAddr = remoteAddr
|
resp.RemoteAddr = remoteAddr
|
||||||
ctl.conn.Info("new proxy [%s] success", m.ProxyName)
|
xl.Info("new proxy [%s] success", m.ProxyName)
|
||||||
ctl.statsCollector.Mark(stats.TypeNewProxy, &stats.NewProxyPayload{
|
ctl.statsCollector.Mark(stats.TypeNewProxy, &stats.NewProxyPayload{
|
||||||
Name: m.ProxyName,
|
Name: m.ProxyName,
|
||||||
ProxyType: m.ProxyType,
|
ProxyType: m.ProxyType,
|
||||||
@ -412,10 +426,10 @@ func (ctl *Control) manager() {
|
|||||||
ctl.sendCh <- resp
|
ctl.sendCh <- resp
|
||||||
case *msg.CloseProxy:
|
case *msg.CloseProxy:
|
||||||
ctl.CloseProxy(m)
|
ctl.CloseProxy(m)
|
||||||
ctl.conn.Info("close proxy [%s] success", m.ProxyName)
|
xl.Info("close proxy [%s] success", m.ProxyName)
|
||||||
case *msg.Ping:
|
case *msg.Ping:
|
||||||
ctl.lastPing = time.Now()
|
ctl.lastPing = time.Now()
|
||||||
ctl.conn.Debug("receive heartbeat")
|
xl.Debug("receive heartbeat")
|
||||||
ctl.sendCh <- &msg.Pong{}
|
ctl.sendCh <- &msg.Pong{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -432,7 +446,7 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
|
|||||||
|
|
||||||
// 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, ctl.serverCfg)
|
pxy, err := proxy.NewProxy(ctl.ctx, 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
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
@ -55,7 +56,7 @@ func (vm *VisitorManager) Listen(name string, sk string) (l *frpNet.CustomListen
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vm *VisitorManager) NewConn(name string, conn frpNet.Conn, timestamp int64, signKey string,
|
func (vm *VisitorManager) NewConn(name string, conn net.Conn, timestamp int64, signKey string,
|
||||||
useEncryption bool, useCompression bool) (err error) {
|
useEncryption bool, useCompression bool) (err error) {
|
||||||
|
|
||||||
vm.mu.RLock()
|
vm.mu.RLock()
|
||||||
|
@ -2,11 +2,10 @@ package group
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/vhost"
|
"github.com/fatedier/frp/utils/vhost"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -131,7 +130,7 @@ func (g *HTTPGroup) UnRegister(proxyName string) (isEmpty bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *HTTPGroup) createConn(remoteAddr string) (frpNet.Conn, error) {
|
func (g *HTTPGroup) createConn(remoteAddr string) (net.Conn, error) {
|
||||||
var f vhost.CreateConnFunc
|
var f vhost.CreateConnFunc
|
||||||
newIndex := atomic.AddUint64(&g.index, 1)
|
newIndex := atomic.AddUint64(&g.index, 1)
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ type HttpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
routeConfig := vhost.VhostRouteConfig{
|
routeConfig := vhost.VhostRouteConfig{
|
||||||
RewriteHost: pxy.cfg.HostHeaderRewrite,
|
RewriteHost: pxy.cfg.HostHeaderRewrite,
|
||||||
Headers: pxy.cfg.Headers,
|
Headers: pxy.cfg.Headers,
|
||||||
@ -88,7 +89,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(pxy.serverCfg.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)
|
xl.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ func (pxy *HttpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
addrs = append(addrs, util.CanonicalAddr(tmpDomain, pxy.serverCfg.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)
|
xl.Info("http proxy listen for host [%s] location [%s] group [%s]", routeConfig.Domain, routeConfig.Location, pxy.cfg.Group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remoteAddr = strings.Join(addrs, ",")
|
remoteAddr = strings.Join(addrs, ",")
|
||||||
@ -131,10 +132,11 @@ func (pxy *HttpProxy) GetConf() config.ProxyConf {
|
|||||||
return pxy.cfg
|
return pxy.cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpProxy) GetRealConn(remoteAddr string) (workConn frpNet.Conn, err error) {
|
func (pxy *HttpProxy) GetRealConn(remoteAddr string) (workConn net.Conn, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr)
|
rAddr, errRet := net.ResolveTCPAddr("tcp", remoteAddr)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
pxy.Warn("resolve TCP addr [%s] error: %v", remoteAddr, errRet)
|
xl.Warn("resolve TCP addr [%s] error: %v", remoteAddr, errRet)
|
||||||
// we do not return error here since remoteAddr is not necessary for proxies without proxy protocol enabled
|
// we do not return error here since remoteAddr is not necessary for proxies without proxy protocol enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +150,7 @@ func (pxy *HttpProxy) GetRealConn(remoteAddr string) (workConn frpNet.Conn, err
|
|||||||
if pxy.cfg.UseEncryption {
|
if pxy.cfg.UseEncryption {
|
||||||
rwc, err = frpIo.WithEncryption(rwc, []byte(pxy.serverCfg.Token))
|
rwc, err = frpIo.WithEncryption(rwc, []byte(pxy.serverCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
xl.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ type HttpsProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
routeConfig := &vhost.VhostRouteConfig{}
|
routeConfig := &vhost.VhostRouteConfig{}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -42,26 +43,24 @@ func (pxy *HttpsProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
routeConfig.Domain = domain
|
routeConfig.Domain = domain
|
||||||
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(routeConfig)
|
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(pxy.ctx, routeConfig)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.AddLogPrefix(pxy.name)
|
xl.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, pxy.serverCfg.VhostHttpsPort))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHttpsPort))
|
||||||
}
|
}
|
||||||
|
|
||||||
if pxy.cfg.SubDomain != "" {
|
if pxy.cfg.SubDomain != "" {
|
||||||
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
routeConfig.Domain = pxy.cfg.SubDomain + "." + pxy.serverCfg.SubDomainHost
|
||||||
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(routeConfig)
|
l, errRet := pxy.rc.VhostHttpsMuxer.Listen(pxy.ctx, routeConfig)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
l.AddLogPrefix(pxy.name)
|
xl.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(pxy.serverCfg.VhostHttpsPort)))
|
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(pxy.serverCfg.VhostHttpsPort)))
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -25,48 +26,54 @@ import (
|
|||||||
"github.com/fatedier/frp/models/msg"
|
"github.com/fatedier/frp/models/msg"
|
||||||
"github.com/fatedier/frp/server/controller"
|
"github.com/fatedier/frp/server/controller"
|
||||||
"github.com/fatedier/frp/server/stats"
|
"github.com/fatedier/frp/server/stats"
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
frpIo "github.com/fatedier/golib/io"
|
frpIo "github.com/fatedier/golib/io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GetWorkConnFn func() (frpNet.Conn, error)
|
type GetWorkConnFn func() (net.Conn, error)
|
||||||
|
|
||||||
type Proxy interface {
|
type Proxy interface {
|
||||||
|
Context() context.Context
|
||||||
Run() (remoteAddr string, err error)
|
Run() (remoteAddr string, err error)
|
||||||
GetName() string
|
GetName() string
|
||||||
GetConf() config.ProxyConf
|
GetConf() config.ProxyConf
|
||||||
GetWorkConnFromPool(src, dst net.Addr) (workConn frpNet.Conn, err error)
|
GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn, err error)
|
||||||
GetUsedPortsNum() int
|
GetUsedPortsNum() int
|
||||||
Close()
|
Close()
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseProxy struct {
|
type BaseProxy struct {
|
||||||
name string
|
name string
|
||||||
rc *controller.ResourceController
|
rc *controller.ResourceController
|
||||||
statsCollector stats.Collector
|
statsCollector stats.Collector
|
||||||
listeners []frpNet.Listener
|
listeners []net.Listener
|
||||||
usedPortsNum int
|
usedPortsNum int
|
||||||
poolCount int
|
poolCount int
|
||||||
getWorkConnFn GetWorkConnFn
|
getWorkConnFn GetWorkConnFn
|
||||||
serverCfg config.ServerCommonConf
|
serverCfg config.ServerCommonConf
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
log.Logger
|
xl *xlog.Logger
|
||||||
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *BaseProxy) GetName() string {
|
func (pxy *BaseProxy) GetName() string {
|
||||||
return pxy.name
|
return pxy.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pxy *BaseProxy) Context() context.Context {
|
||||||
|
return pxy.ctx
|
||||||
|
}
|
||||||
|
|
||||||
func (pxy *BaseProxy) GetUsedPortsNum() int {
|
func (pxy *BaseProxy) GetUsedPortsNum() int {
|
||||||
return pxy.usedPortsNum
|
return pxy.usedPortsNum
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *BaseProxy) Close() {
|
func (pxy *BaseProxy) Close() {
|
||||||
pxy.Info("proxy closing")
|
xl := xlog.FromContextSafe(pxy.ctx)
|
||||||
|
xl.Info("proxy closing")
|
||||||
for _, l := range pxy.listeners {
|
for _, l := range pxy.listeners {
|
||||||
l.Close()
|
l.Close()
|
||||||
}
|
}
|
||||||
@ -74,15 +81,17 @@ func (pxy *BaseProxy) Close() {
|
|||||||
|
|
||||||
// GetWorkConnFromPool try to get a new work connections from pool
|
// GetWorkConnFromPool try to get a new work connections from pool
|
||||||
// for quickly response, we immediately send the StartWorkConn message to frpc after take out one from pool
|
// for quickly response, we immediately send the StartWorkConn message to frpc after take out one from pool
|
||||||
func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn frpNet.Conn, err error) {
|
func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn, err error) {
|
||||||
|
xl := xlog.FromContextSafe(pxy.ctx)
|
||||||
// try all connections from the pool
|
// try all connections from the pool
|
||||||
for i := 0; i < pxy.poolCount+1; i++ {
|
for i := 0; i < pxy.poolCount+1; i++ {
|
||||||
if workConn, err = pxy.getWorkConnFn(); err != nil {
|
if workConn, err = pxy.getWorkConnFn(); err != nil {
|
||||||
pxy.Warn("failed to get work connection: %v", err)
|
xl.Warn("failed to get work connection: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pxy.Info("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
xl.Info("get a new work connection: [%s]", workConn.RemoteAddr().String())
|
||||||
workConn.AddLogPrefix(pxy.GetName())
|
xl.Spawn().AppendPrefix(pxy.GetName())
|
||||||
|
workConn = frpNet.NewContextConn(workConn, pxy.ctx)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
srcAddr string
|
srcAddr string
|
||||||
@ -109,7 +118,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn frpNet.Co
|
|||||||
DstPort: uint16(dstPort),
|
DstPort: uint16(dstPort),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
workConn.Warn("failed to send message to work connection from pool: %v, times: %d", err, i)
|
xl.Warn("failed to send message to work connection from pool: %v, times: %d", err, i)
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
@ -117,7 +126,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn frpNet.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("try to get work connection failed in the end")
|
xl.Error("try to get work connection failed in the end")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -126,36 +135,39 @@ 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, config.ServerCommonConf)) {
|
func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn, stats.Collector, config.ServerCommonConf)) {
|
||||||
|
xl := xlog.FromContextSafe(pxy.ctx)
|
||||||
for _, listener := range pxy.listeners {
|
for _, listener := range pxy.listeners {
|
||||||
go func(l frpNet.Listener) {
|
go func(l net.Listener) {
|
||||||
for {
|
for {
|
||||||
// block
|
// block
|
||||||
// if listener is closed, err returned
|
// if listener is closed, err returned
|
||||||
c, err := l.Accept()
|
c, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Info("listener is closed")
|
xl.Info("listener is closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pxy.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
xl.Debug("get a user connection [%s]", c.RemoteAddr().String())
|
||||||
go handler(p, c, pxy.statsCollector, pxy.serverCfg)
|
go handler(p, c, pxy.statsCollector, pxy.serverCfg)
|
||||||
}
|
}
|
||||||
}(listener)
|
}(listener)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProxy(runId string, rc *controller.ResourceController, statsCollector stats.Collector, poolCount int,
|
func NewProxy(ctx context.Context, runId string, rc *controller.ResourceController, statsCollector stats.Collector, poolCount int,
|
||||||
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf) (pxy Proxy, err error) {
|
getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf) (pxy Proxy, err error) {
|
||||||
|
|
||||||
|
xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName)
|
||||||
basePxy := BaseProxy{
|
basePxy := BaseProxy{
|
||||||
name: pxyConf.GetBaseInfo().ProxyName,
|
name: pxyConf.GetBaseInfo().ProxyName,
|
||||||
rc: rc,
|
rc: rc,
|
||||||
statsCollector: statsCollector,
|
statsCollector: statsCollector,
|
||||||
listeners: make([]frpNet.Listener, 0),
|
listeners: make([]net.Listener, 0),
|
||||||
poolCount: poolCount,
|
poolCount: poolCount,
|
||||||
getWorkConnFn: getWorkConnFn,
|
getWorkConnFn: getWorkConnFn,
|
||||||
Logger: log.NewPrefixLogger(runId),
|
|
||||||
serverCfg: serverCfg,
|
serverCfg: serverCfg,
|
||||||
|
xl: xl,
|
||||||
|
ctx: xlog.NewContext(ctx, xl),
|
||||||
}
|
}
|
||||||
switch cfg := pxyConf.(type) {
|
switch cfg := pxyConf.(type) {
|
||||||
case *config.TcpProxyConf:
|
case *config.TcpProxyConf:
|
||||||
@ -193,13 +205,13 @@ func NewProxy(runId string, rc *controller.ResourceController, statsCollector st
|
|||||||
default:
|
default:
|
||||||
return pxy, fmt.Errorf("proxy type not support")
|
return pxy, fmt.Errorf("proxy type not support")
|
||||||
}
|
}
|
||||||
pxy.AddLogPrefix(pxy.GetName())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, serverCfg config.ServerCommonConf) {
|
func HandleUserTcpConnection(pxy Proxy, userConn net.Conn, statsCollector stats.Collector, serverCfg config.ServerCommonConf) {
|
||||||
|
xl := xlog.FromContextSafe(pxy.Context())
|
||||||
defer userConn.Close()
|
defer userConn.Close()
|
||||||
|
|
||||||
// try all connections from the pool
|
// try all connections from the pool
|
||||||
@ -211,17 +223,18 @@ 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()
|
||||||
|
xl.Trace("handler user tcp connection, use_encryption: %t, use_compression: %t", cfg.UseEncryption, cfg.UseCompression)
|
||||||
if cfg.UseEncryption {
|
if cfg.UseEncryption {
|
||||||
local, err = frpIo.WithEncryption(local, []byte(serverCfg.Token))
|
local, err = frpIo.WithEncryption(local, []byte(serverCfg.Token))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pxy.Error("create encryption stream error: %v", err)
|
xl.Error("create encryption stream error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.UseCompression {
|
if cfg.UseCompression {
|
||||||
local = frpIo.WithCompression(local)
|
local = frpIo.WithCompression(local)
|
||||||
}
|
}
|
||||||
pxy.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
|
xl.Debug("join connections, workConn(l[%s] r[%s]) userConn(l[%s] r[%s])", workConn.LocalAddr().String(),
|
||||||
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
workConn.RemoteAddr().String(), userConn.LocalAddr().String(), userConn.RemoteAddr().String())
|
||||||
|
|
||||||
statsCollector.Mark(stats.TypeOpenConnection, &stats.OpenConnectionPayload{ProxyName: pxy.GetName()})
|
statsCollector.Mark(stats.TypeOpenConnection, &stats.OpenConnectionPayload{ProxyName: pxy.GetName()})
|
||||||
@ -235,7 +248,7 @@ func HandleUserTcpConnection(pxy Proxy, userConn frpNet.Conn, statsCollector sta
|
|||||||
ProxyName: pxy.GetName(),
|
ProxyName: pxy.GetName(),
|
||||||
TrafficBytes: outCount,
|
TrafficBytes: outCount,
|
||||||
})
|
})
|
||||||
pxy.Debug("join connections closed")
|
xl.Debug("join connections closed")
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProxyManager struct {
|
type ProxyManager struct {
|
||||||
|
@ -24,14 +24,14 @@ type StcpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *StcpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *StcpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
listener, errRet := pxy.rc.VisitorManager.Listen(pxy.GetName(), pxy.cfg.Sk)
|
listener, errRet := pxy.rc.VisitorManager.Listen(pxy.GetName(), pxy.cfg.Sk)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listener.AddLogPrefix(pxy.name)
|
|
||||||
pxy.listeners = append(pxy.listeners, listener)
|
pxy.listeners = append(pxy.listeners, listener)
|
||||||
pxy.Info("stcp proxy custom listen success")
|
xl.Info("stcp proxy custom listen success")
|
||||||
|
|
||||||
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
pxy.startListenHandler(pxy, HandleUserTcpConnection)
|
||||||
return
|
return
|
||||||
|
@ -16,9 +16,9 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/fatedier/frp/models/config"
|
"github.com/fatedier/frp/models/config"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TcpProxy struct {
|
type TcpProxy struct {
|
||||||
@ -29,6 +29,7 @@ type TcpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
if pxy.cfg.Group != "" {
|
if pxy.cfg.Group != "" {
|
||||||
l, realPort, errRet := pxy.rc.TcpGroupCtl.Listen(pxy.name, pxy.cfg.Group, pxy.cfg.GroupKey, pxy.serverCfg.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 {
|
||||||
@ -41,10 +42,8 @@ func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
pxy.realPort = realPort
|
pxy.realPort = realPort
|
||||||
listener := frpNet.WrapLogListener(l)
|
pxy.listeners = append(pxy.listeners, l)
|
||||||
listener.AddLogPrefix(pxy.name)
|
xl.Info("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.Group)
|
||||||
pxy.listeners = append(pxy.listeners, listener)
|
|
||||||
pxy.Info("tcp proxy listen port [%d] in group [%s]", pxy.cfg.RemotePort, pxy.cfg.Group)
|
|
||||||
} else {
|
} else {
|
||||||
pxy.realPort, err = pxy.rc.TcpPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
|
pxy.realPort, err = pxy.rc.TcpPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -55,14 +54,13 @@ func (pxy *TcpProxy) Run() (remoteAddr string, err error) {
|
|||||||
pxy.rc.TcpPortManager.Release(pxy.realPort)
|
pxy.rc.TcpPortManager.Release(pxy.realPort)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
listener, errRet := frpNet.ListenTcp(pxy.serverCfg.ProxyBindAddr, pxy.realPort)
|
listener, errRet := net.Listen("tcp", fmt.Sprintf("%s:%d", pxy.serverCfg.ProxyBindAddr, pxy.realPort))
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listener.AddLogPrefix(pxy.name)
|
|
||||||
pxy.listeners = append(pxy.listeners, listener)
|
pxy.listeners = append(pxy.listeners, listener)
|
||||||
pxy.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort)
|
xl.Info("tcp proxy listen port [%d]", pxy.cfg.RemotePort)
|
||||||
}
|
}
|
||||||
|
|
||||||
pxy.cfg.RemotePort = pxy.realPort
|
pxy.cfg.RemotePort = pxy.realPort
|
||||||
|
@ -54,6 +54,7 @@ type UdpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
pxy.realPort, err = pxy.rc.UdpPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
|
pxy.realPort, err = pxy.rc.UdpPortManager.Acquire(pxy.name, pxy.cfg.RemotePort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -74,10 +75,10 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
udpConn, errRet := net.ListenUDP("udp", addr)
|
udpConn, errRet := net.ListenUDP("udp", addr)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = errRet
|
err = errRet
|
||||||
pxy.Warn("listen udp port error: %v", err)
|
xl.Warn("listen udp port error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pxy.Info("udp proxy listen port [%d]", pxy.cfg.RemotePort)
|
xl.Info("udp proxy listen port [%d]", pxy.cfg.RemotePort)
|
||||||
|
|
||||||
pxy.udpConn = udpConn
|
pxy.udpConn = udpConn
|
||||||
pxy.sendCh = make(chan *msg.UdpPacket, 1024)
|
pxy.sendCh = make(chan *msg.UdpPacket, 1024)
|
||||||
@ -91,11 +92,11 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
rawMsg msg.Message
|
rawMsg msg.Message
|
||||||
errRet error
|
errRet error
|
||||||
)
|
)
|
||||||
pxy.Trace("loop waiting message from udp workConn")
|
xl.Trace("loop waiting message from udp workConn")
|
||||||
// client will send heartbeat in workConn for keeping alive
|
// client will send heartbeat in workConn for keeping alive
|
||||||
conn.SetReadDeadline(time.Now().Add(time.Duration(60) * time.Second))
|
conn.SetReadDeadline(time.Now().Add(time.Duration(60) * time.Second))
|
||||||
if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
|
if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
|
||||||
pxy.Warn("read from workConn for udp error: %v", errRet)
|
xl.Warn("read from workConn for udp error: %v", errRet)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
// notify proxy to start a new work connection
|
// notify proxy to start a new work connection
|
||||||
// ignore error here, it means the proxy is closed
|
// ignore error here, it means the proxy is closed
|
||||||
@ -107,11 +108,11 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
conn.SetReadDeadline(time.Time{})
|
conn.SetReadDeadline(time.Time{})
|
||||||
switch m := rawMsg.(type) {
|
switch m := rawMsg.(type) {
|
||||||
case *msg.Ping:
|
case *msg.Ping:
|
||||||
pxy.Trace("udp work conn get ping message")
|
xl.Trace("udp work conn get ping message")
|
||||||
continue
|
continue
|
||||||
case *msg.UdpPacket:
|
case *msg.UdpPacket:
|
||||||
if errRet := errors.PanicToError(func() {
|
if errRet := errors.PanicToError(func() {
|
||||||
pxy.Trace("get udp message from workConn: %s", m.Content)
|
xl.Trace("get udp message from workConn: %s", m.Content)
|
||||||
pxy.readCh <- m
|
pxy.readCh <- m
|
||||||
pxy.statsCollector.Mark(stats.TypeAddTrafficOut, &stats.AddTrafficOutPayload{
|
pxy.statsCollector.Mark(stats.TypeAddTrafficOut, &stats.AddTrafficOutPayload{
|
||||||
ProxyName: pxy.GetName(),
|
ProxyName: pxy.GetName(),
|
||||||
@ -119,7 +120,7 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
})
|
})
|
||||||
}); errRet != nil {
|
}); errRet != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
pxy.Info("reader goroutine for udp work connection closed")
|
xl.Info("reader goroutine for udp work connection closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,15 +134,15 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
select {
|
select {
|
||||||
case udpMsg, ok := <-pxy.sendCh:
|
case udpMsg, ok := <-pxy.sendCh:
|
||||||
if !ok {
|
if !ok {
|
||||||
pxy.Info("sender goroutine for udp work connection closed")
|
xl.Info("sender goroutine for udp work connection closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if errRet = msg.WriteMsg(conn, udpMsg); errRet != nil {
|
if errRet = msg.WriteMsg(conn, udpMsg); errRet != nil {
|
||||||
pxy.Info("sender goroutine for udp work connection closed: %v", errRet)
|
xl.Info("sender goroutine for udp work connection closed: %v", errRet)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
pxy.Trace("send message to udp workConn: %s", udpMsg.Content)
|
xl.Trace("send message to udp workConn: %s", udpMsg.Content)
|
||||||
pxy.statsCollector.Mark(stats.TypeAddTrafficIn, &stats.AddTrafficInPayload{
|
pxy.statsCollector.Mark(stats.TypeAddTrafficIn, &stats.AddTrafficInPayload{
|
||||||
ProxyName: pxy.GetName(),
|
ProxyName: pxy.GetName(),
|
||||||
TrafficBytes: int64(len(udpMsg.Content)),
|
TrafficBytes: int64(len(udpMsg.Content)),
|
||||||
@ -149,7 +150,7 @@ func (pxy *UdpProxy) Run() (remoteAddr string, err error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
pxy.Info("sender goroutine for udp work connection closed")
|
xl.Info("sender goroutine for udp work connection closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@ type XtcpProxy struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pxy *XtcpProxy) Run() (remoteAddr string, err error) {
|
func (pxy *XtcpProxy) Run() (remoteAddr string, err error) {
|
||||||
|
xl := pxy.xl
|
||||||
|
|
||||||
if pxy.rc.NatHoleController == nil {
|
if pxy.rc.NatHoleController == nil {
|
||||||
pxy.Error("udp port for xtcp is not specified.")
|
xl.Error("udp port for xtcp is not specified.")
|
||||||
err = fmt.Errorf("xtcp is not supported in frps")
|
err = fmt.Errorf("xtcp is not supported in frps")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -53,7 +55,7 @@ func (pxy *XtcpProxy) Run() (remoteAddr string, err error) {
|
|||||||
}
|
}
|
||||||
errRet = msg.WriteMsg(workConn, m)
|
errRet = msg.WriteMsg(workConn, m)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
pxy.Warn("write nat hole sid package error, %v", errRet)
|
xl.Warn("write nat hole sid package error, %v", errRet)
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -61,12 +63,12 @@ func (pxy *XtcpProxy) Run() (remoteAddr string, err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
raw, errRet := msg.ReadMsg(workConn)
|
raw, errRet := msg.ReadMsg(workConn)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
pxy.Warn("read nat hole client ok package error: %v", errRet)
|
xl.Warn("read nat hole client ok package error: %v", errRet)
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, ok := raw.(*msg.NatHoleClientDetectOK); !ok {
|
if _, ok := raw.(*msg.NatHoleClientDetectOK); !ok {
|
||||||
pxy.Warn("read nat hole client ok package format error")
|
xl.Warn("read nat hole client ok package format error")
|
||||||
workConn.Close()
|
workConn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
@ -42,6 +43,7 @@ import (
|
|||||||
"github.com/fatedier/frp/utils/util"
|
"github.com/fatedier/frp/utils/util"
|
||||||
"github.com/fatedier/frp/utils/version"
|
"github.com/fatedier/frp/utils/version"
|
||||||
"github.com/fatedier/frp/utils/vhost"
|
"github.com/fatedier/frp/utils/vhost"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
"github.com/fatedier/golib/net/mux"
|
"github.com/fatedier/golib/net/mux"
|
||||||
fmux "github.com/hashicorp/yamux"
|
fmux "github.com/hashicorp/yamux"
|
||||||
@ -57,16 +59,16 @@ type Service struct {
|
|||||||
muxer *mux.Mux
|
muxer *mux.Mux
|
||||||
|
|
||||||
// Accept connections from client
|
// Accept connections from client
|
||||||
listener frpNet.Listener
|
listener net.Listener
|
||||||
|
|
||||||
// Accept connections using kcp
|
// Accept connections using kcp
|
||||||
kcpListener frpNet.Listener
|
kcpListener net.Listener
|
||||||
|
|
||||||
// Accept connections using websocket
|
// Accept connections using websocket
|
||||||
websocketListener frpNet.Listener
|
websocketListener net.Listener
|
||||||
|
|
||||||
// Accept frp tls connections
|
// Accept frp tls connections
|
||||||
tlsListener frpNet.Listener
|
tlsListener net.Listener
|
||||||
|
|
||||||
// Manage all controllers
|
// Manage all controllers
|
||||||
ctlManager *ControlManager
|
ctlManager *ControlManager
|
||||||
@ -135,7 +137,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
|
|||||||
go svr.muxer.Serve()
|
go svr.muxer.Serve()
|
||||||
ln = svr.muxer.DefaultListener()
|
ln = svr.muxer.DefaultListener()
|
||||||
|
|
||||||
svr.listener = frpNet.WrapLogListener(ln)
|
svr.listener = ln
|
||||||
log.Info("frps tcp listen on %s:%d", cfg.BindAddr, cfg.BindPort)
|
log.Info("frps tcp listen on %s:%d", cfg.BindAddr, cfg.BindPort)
|
||||||
|
|
||||||
// Listen for accepting connections from client using kcp protocol.
|
// Listen for accepting connections from client using kcp protocol.
|
||||||
@ -194,7 +196,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svr.rc.VhostHttpsMuxer, err = vhost.NewHttpsMuxer(frpNet.WrapLogListener(l), 30*time.Second)
|
svr.rc.VhostHttpsMuxer, err = vhost.NewHttpsMuxer(l, 30*time.Second)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("Create vhost httpsMuxer error, %v", err)
|
err = fmt.Errorf("Create vhost httpsMuxer error, %v", err)
|
||||||
return
|
return
|
||||||
@ -203,10 +205,9 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// frp tls listener
|
// frp tls listener
|
||||||
tlsListener := svr.muxer.Listen(1, 1, func(data []byte) bool {
|
svr.tlsListener = svr.muxer.Listen(1, 1, func(data []byte) bool {
|
||||||
return int(data[0]) == frpNet.FRP_TLS_HEAD_BYTE
|
return int(data[0]) == frpNet.FRP_TLS_HEAD_BYTE
|
||||||
})
|
})
|
||||||
svr.tlsListener = frpNet.WrapLogListener(tlsListener)
|
|
||||||
|
|
||||||
// Create nat hole controller.
|
// Create nat hole controller.
|
||||||
if cfg.BindUdpPort > 0 {
|
if cfg.BindUdpPort > 0 {
|
||||||
@ -258,7 +259,7 @@ func (svr *Service) Run() {
|
|||||||
svr.HandleListener(svr.listener)
|
svr.HandleListener(svr.listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Service) HandleListener(l frpNet.Listener) {
|
func (svr *Service) HandleListener(l net.Listener) {
|
||||||
// Listen for incoming connections from client.
|
// Listen for incoming connections from client.
|
||||||
for {
|
for {
|
||||||
c, err := l.Accept()
|
c, err := l.Accept()
|
||||||
@ -266,6 +267,9 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
log.Warn("Listener for incoming connections from client closed")
|
log.Warn("Listener for incoming connections from client closed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// inject xlog object into net.Conn context
|
||||||
|
xl := xlog.New()
|
||||||
|
c = frpNet.NewContextConn(c, xlog.NewContext(context.Background(), xl))
|
||||||
|
|
||||||
log.Trace("start check TLS connection...")
|
log.Trace("start check TLS connection...")
|
||||||
originConn := c
|
originConn := c
|
||||||
@ -278,8 +282,8 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
log.Trace("success check TLS connection")
|
log.Trace("success check TLS connection")
|
||||||
|
|
||||||
// Start a new goroutine for dealing connections.
|
// Start a new goroutine for dealing connections.
|
||||||
go func(frpConn frpNet.Conn) {
|
go func(frpConn net.Conn) {
|
||||||
dealFn := func(conn frpNet.Conn) {
|
dealFn := func(conn net.Conn) {
|
||||||
var rawMsg msg.Message
|
var rawMsg msg.Message
|
||||||
conn.SetReadDeadline(time.Now().Add(connReadTimeout))
|
conn.SetReadDeadline(time.Now().Add(connReadTimeout))
|
||||||
if rawMsg, err = msg.ReadMsg(conn); err != nil {
|
if rawMsg, err = msg.ReadMsg(conn); err != nil {
|
||||||
@ -295,7 +299,7 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
// If login failed, send error message there.
|
// If login failed, send error message there.
|
||||||
// Otherwise send success message in control's work goroutine.
|
// Otherwise send success message in control's work goroutine.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.Warn("%v", err)
|
xl.Warn("register control error: %v", err)
|
||||||
msg.WriteMsg(conn, &msg.LoginResp{
|
msg.WriteMsg(conn, &msg.LoginResp{
|
||||||
Version: version.Full(),
|
Version: version.Full(),
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
@ -306,7 +310,7 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
svr.RegisterWorkConn(conn, m)
|
svr.RegisterWorkConn(conn, m)
|
||||||
case *msg.NewVisitorConn:
|
case *msg.NewVisitorConn:
|
||||||
if err = svr.RegisterVisitorConn(conn, m); err != nil {
|
if err = svr.RegisterVisitorConn(conn, m); err != nil {
|
||||||
conn.Warn("%v", err)
|
xl.Warn("register visitor conn error: %v", err)
|
||||||
msg.WriteMsg(conn, &msg.NewVisitorConnResp{
|
msg.WriteMsg(conn, &msg.NewVisitorConnResp{
|
||||||
ProxyName: m.ProxyName,
|
ProxyName: m.ProxyName,
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
@ -342,8 +346,7 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
session.Close()
|
session.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wrapConn := frpNet.WrapConn(stream)
|
go dealFn(stream)
|
||||||
go dealFn(wrapConn)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dealFn(frpConn)
|
dealFn(frpConn)
|
||||||
@ -352,8 +355,21 @@ func (svr *Service) HandleListener(l frpNet.Listener) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (err error) {
|
func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err error) {
|
||||||
ctlConn.Info("client login info: ip [%s] version [%s] hostname [%s] os [%s] arch [%s]",
|
// If client's RunId is empty, it's a new client, we just create a new controller.
|
||||||
|
// Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one.
|
||||||
|
if loginMsg.RunId == "" {
|
||||||
|
loginMsg.RunId, err = util.RandId()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := frpNet.NewContextFromConn(ctlConn)
|
||||||
|
xl := xlog.FromContextSafe(ctx)
|
||||||
|
xl.AppendPrefix(loginMsg.RunId)
|
||||||
|
ctx = xlog.NewContext(ctx, xl)
|
||||||
|
xl.Info("client login info: ip [%s] version [%s] hostname [%s] os [%s] arch [%s]",
|
||||||
ctlConn.RemoteAddr().String(), loginMsg.Version, loginMsg.Hostname, loginMsg.Os, loginMsg.Arch)
|
ctlConn.RemoteAddr().String(), loginMsg.Version, loginMsg.Hostname, loginMsg.Os, loginMsg.Arch)
|
||||||
|
|
||||||
// Check client version.
|
// Check client version.
|
||||||
@ -368,22 +384,12 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If client's RunId is empty, it's a new client, we just create a new controller.
|
ctl := NewControl(ctx, svr.rc, svr.pxyManager, svr.statsCollector, ctlConn, loginMsg, svr.cfg)
|
||||||
// Otherwise, we check if there is one controller has the same run id. If so, we release previous controller and start new one.
|
|
||||||
if loginMsg.RunId == "" {
|
|
||||||
loginMsg.RunId, err = util.RandId()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctlConn.AddLogPrefix(loginMsg.RunId)
|
|
||||||
ctl.Start()
|
ctl.Start()
|
||||||
|
|
||||||
// for statistics
|
// for statistics
|
||||||
@ -398,17 +404,18 @@ func (svr *Service) RegisterControl(ctlConn frpNet.Conn, loginMsg *msg.Login) (e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterWorkConn register a new work connection to control and proxies need it.
|
// RegisterWorkConn register a new work connection to control and proxies need it.
|
||||||
func (svr *Service) RegisterWorkConn(workConn frpNet.Conn, newMsg *msg.NewWorkConn) {
|
func (svr *Service) RegisterWorkConn(workConn net.Conn, newMsg *msg.NewWorkConn) {
|
||||||
|
xl := frpNet.NewLogFromConn(workConn)
|
||||||
ctl, exist := svr.ctlManager.GetById(newMsg.RunId)
|
ctl, exist := svr.ctlManager.GetById(newMsg.RunId)
|
||||||
if !exist {
|
if !exist {
|
||||||
workConn.Warn("No client control found for run id [%s]", newMsg.RunId)
|
xl.Warn("No client control found for run id [%s]", newMsg.RunId)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctl.RegisterWorkConn(workConn)
|
ctl.RegisterWorkConn(workConn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svr *Service) RegisterVisitorConn(visitorConn frpNet.Conn, newMsg *msg.NewVisitorConn) error {
|
func (svr *Service) RegisterVisitorConn(visitorConn net.Conn, newMsg *msg.NewVisitorConn) error {
|
||||||
return svr.rc.VisitorManager.NewConn(newMsg.ProxyName, visitorConn, newMsg.Timestamp, newMsg.SignKey,
|
return svr.rc.VisitorManager.NewConn(newMsg.ProxyName, visitorConn, newMsg.Timestamp, newMsg.SignKey,
|
||||||
newMsg.UseEncryption, newMsg.UseCompression)
|
newMsg.UseEncryption, newMsg.UseCompression)
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
server_addr = 127.0.0.1
|
server_addr = 127.0.0.1
|
||||||
server_port = 10700
|
server_port = 10700
|
||||||
log_file = console
|
log_file = console
|
||||||
# debug, info, warn, error
|
log_level = trace
|
||||||
log_level = debug
|
|
||||||
token = 123456
|
token = 123456
|
||||||
admin_port = 10600
|
admin_port = 10600
|
||||||
admin_user = abc
|
admin_user = abc
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
bind_addr = 0.0.0.0
|
bind_addr = 0.0.0.0
|
||||||
bind_port = 10700
|
bind_port = 10700
|
||||||
vhost_http_port = 10804
|
vhost_http_port = 10804
|
||||||
log_file = console
|
log_level = trace
|
||||||
log_level = debug
|
|
||||||
token = 123456
|
token = 123456
|
||||||
allow_ports = 10000-20000,20002,30000-50000
|
allow_ports = 10000-20000,20002,30000-50000
|
||||||
subdomain_host = sub.com
|
subdomain_host = sub.com
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EchoServer struct {
|
type EchoServer struct {
|
||||||
l frpNet.Listener
|
l net.Listener
|
||||||
|
|
||||||
port int
|
port int
|
||||||
repeatedNum int
|
repeatedNum int
|
||||||
@ -30,7 +30,7 @@ func NewEchoServer(port int, repeatedNum int, specifyStr string) *EchoServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (es *EchoServer) Start() error {
|
func (es *EchoServer) Start() error {
|
||||||
l, err := frpNet.ListenTcp("127.0.0.1", es.port)
|
l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", es.port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("echo server listen error: %v\n", err)
|
fmt.Printf("echo server listen error: %v\n", err)
|
||||||
return err
|
return err
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/client"
|
"github.com/fatedier/frp/client"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetProxyStatus(statusAddr string, user string, passwd string, name string) (status *client.ProxyStatusResp, err error) {
|
func GetProxyStatus(statusAddr string, user string, passwd string, name string) (status *client.ProxyStatusResp, err error) {
|
||||||
@ -98,7 +97,7 @@ func ReloadConf(reloadAddr string, user string, passwd string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SendTcpMsg(addr string, msg string) (res string, err error) {
|
func SendTcpMsg(addr string, msg string) (res string, err error) {
|
||||||
c, err := frpNet.ConnectTcpServer(addr)
|
c, err := net.Dial("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("connect to tcp server error: %v", err)
|
err = fmt.Errorf("connect to tcp server error: %v", err)
|
||||||
return
|
return
|
||||||
|
@ -91,71 +91,3 @@ func Debug(format string, v ...interface{}) {
|
|||||||
func Trace(format string, v ...interface{}) {
|
func Trace(format string, v ...interface{}) {
|
||||||
Log.Trace(format, v...)
|
Log.Trace(format, v...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logger is the log interface
|
|
||||||
type Logger interface {
|
|
||||||
AddLogPrefix(string)
|
|
||||||
GetPrefixStr() string
|
|
||||||
GetAllPrefix() []string
|
|
||||||
ClearLogPrefix()
|
|
||||||
Error(string, ...interface{})
|
|
||||||
Warn(string, ...interface{})
|
|
||||||
Info(string, ...interface{})
|
|
||||||
Debug(string, ...interface{})
|
|
||||||
Trace(string, ...interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
type PrefixLogger struct {
|
|
||||||
prefix string
|
|
||||||
allPrefix []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPrefixLogger(prefix string) *PrefixLogger {
|
|
||||||
logger := &PrefixLogger{
|
|
||||||
allPrefix: make([]string, 0),
|
|
||||||
}
|
|
||||||
logger.AddLogPrefix(prefix)
|
|
||||||
return logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) AddLogPrefix(prefix string) {
|
|
||||||
if len(prefix) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pl.prefix += "[" + prefix + "] "
|
|
||||||
pl.allPrefix = append(pl.allPrefix, prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) GetPrefixStr() string {
|
|
||||||
return pl.prefix
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) GetAllPrefix() []string {
|
|
||||||
return pl.allPrefix
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) ClearLogPrefix() {
|
|
||||||
pl.prefix = ""
|
|
||||||
pl.allPrefix = make([]string, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) Error(format string, v ...interface{}) {
|
|
||||||
Log.Error(pl.prefix+format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) Warn(format string, v ...interface{}) {
|
|
||||||
Log.Warn(pl.prefix+format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) Info(format string, v ...interface{}) {
|
|
||||||
Log.Info(pl.prefix+format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) Debug(format string, v ...interface{}) {
|
|
||||||
Log.Debug(pl.prefix+format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pl *PrefixLogger) Trace(format string, v ...interface{}) {
|
|
||||||
Log.Trace(pl.prefix+format, v...)
|
|
||||||
}
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -23,41 +24,64 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
gnet "github.com/fatedier/golib/net"
|
gnet "github.com/fatedier/golib/net"
|
||||||
kcp "github.com/fatedier/kcp-go"
|
kcp "github.com/fatedier/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn is the interface of connections used in frp.
|
type ContextGetter interface {
|
||||||
type Conn interface {
|
Context() context.Context
|
||||||
net.Conn
|
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WrapLogConn struct {
|
type ContextSetter interface {
|
||||||
net.Conn
|
WithContext(ctx context.Context)
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapConn(c net.Conn) Conn {
|
func NewLogFromConn(conn net.Conn) *xlog.Logger {
|
||||||
return &WrapLogConn{
|
if c, ok := conn.(ContextGetter); ok {
|
||||||
Conn: c,
|
return xlog.FromContextSafe(c.Context())
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
}
|
||||||
|
return xlog.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContextFromConn(conn net.Conn) context.Context {
|
||||||
|
if c, ok := conn.(ContextGetter); ok {
|
||||||
|
return c.Context()
|
||||||
|
}
|
||||||
|
return context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextConn is the connection with context
|
||||||
|
type ContextConn struct {
|
||||||
|
net.Conn
|
||||||
|
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewContextConn(c net.Conn, ctx context.Context) *ContextConn {
|
||||||
|
return &ContextConn{
|
||||||
|
Conn: c,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ContextConn) WithContext(ctx context.Context) {
|
||||||
|
c.ctx = ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ContextConn) Context() context.Context {
|
||||||
|
return c.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
type WrapReadWriteCloserConn struct {
|
type WrapReadWriteCloserConn struct {
|
||||||
io.ReadWriteCloser
|
io.ReadWriteCloser
|
||||||
log.Logger
|
|
||||||
|
|
||||||
underConn net.Conn
|
underConn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) Conn {
|
func WrapReadWriteCloserToConn(rwc io.ReadWriteCloser, underConn net.Conn) net.Conn {
|
||||||
return &WrapReadWriteCloserConn{
|
return &WrapReadWriteCloserConn{
|
||||||
ReadWriteCloser: rwc,
|
ReadWriteCloser: rwc,
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
underConn: underConn,
|
underConn: underConn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +123,6 @@ func (conn *WrapReadWriteCloserConn) SetWriteDeadline(t time.Time) error {
|
|||||||
|
|
||||||
type CloseNotifyConn struct {
|
type CloseNotifyConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
log.Logger
|
|
||||||
|
|
||||||
// 1 means closed
|
// 1 means closed
|
||||||
closeFlag int32
|
closeFlag int32
|
||||||
@ -108,10 +131,9 @@ type CloseNotifyConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// closeFn will be only called once
|
// closeFn will be only called once
|
||||||
func WrapCloseNotifyConn(c net.Conn, closeFn func()) Conn {
|
func WrapCloseNotifyConn(c net.Conn, closeFn func()) net.Conn {
|
||||||
return &CloseNotifyConn{
|
return &CloseNotifyConn{
|
||||||
Conn: c,
|
Conn: c,
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
closeFn: closeFn,
|
closeFn: closeFn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,7 +150,7 @@ func (cc *CloseNotifyConn) Close() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StatsConn struct {
|
type StatsConn struct {
|
||||||
Conn
|
net.Conn
|
||||||
|
|
||||||
closed int64 // 1 means closed
|
closed int64 // 1 means closed
|
||||||
totalRead int64
|
totalRead int64
|
||||||
@ -136,7 +158,7 @@ type StatsConn struct {
|
|||||||
statsFunc func(totalRead, totalWrite int64)
|
statsFunc func(totalRead, totalWrite int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WrapStatsConn(conn Conn, statsFunc func(total, totalWrite int64)) *StatsConn {
|
func WrapStatsConn(conn net.Conn, statsFunc func(total, totalWrite int64)) *StatsConn {
|
||||||
return &StatsConn{
|
return &StatsConn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
statsFunc: statsFunc,
|
statsFunc: statsFunc,
|
||||||
@ -166,10 +188,10 @@ func (statsConn *StatsConn) Close() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectServer(protocol string, addr string) (c Conn, err error) {
|
func ConnectServer(protocol string, addr string) (c net.Conn, err error) {
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
return ConnectTcpServer(addr)
|
return net.Dial("tcp", addr)
|
||||||
case "kcp":
|
case "kcp":
|
||||||
kcpConn, errRet := kcp.DialWithOptions(addr, nil, 10, 3)
|
kcpConn, errRet := kcp.DialWithOptions(addr, nil, 10, 3)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
@ -184,21 +206,17 @@ func ConnectServer(protocol string, addr string) (c Conn, err error) {
|
|||||||
kcpConn.SetACKNoDelay(false)
|
kcpConn.SetACKNoDelay(false)
|
||||||
kcpConn.SetReadBuffer(4194304)
|
kcpConn.SetReadBuffer(4194304)
|
||||||
kcpConn.SetWriteBuffer(4194304)
|
kcpConn.SetWriteBuffer(4194304)
|
||||||
c = WrapConn(kcpConn)
|
c = kcpConn
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupport protocol: %s", protocol)
|
return nil, fmt.Errorf("unsupport protocol: %s", protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectServerByProxy(proxyUrl string, protocol string, addr string) (c Conn, err error) {
|
func ConnectServerByProxy(proxyURL string, protocol string, addr string) (c net.Conn, err error) {
|
||||||
switch protocol {
|
switch protocol {
|
||||||
case "tcp":
|
case "tcp":
|
||||||
var conn net.Conn
|
return gnet.DialTcpByProxy(proxyURL, addr)
|
||||||
if conn, err = gnet.DialTcpByProxy(proxyUrl, addr); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return WrapConn(conn), nil
|
|
||||||
case "kcp":
|
case "kcp":
|
||||||
// http proxy is not supported for kcp
|
// http proxy is not supported for kcp
|
||||||
return ConnectServer(protocol, addr)
|
return ConnectServer(protocol, addr)
|
||||||
@ -209,7 +227,7 @@ func ConnectServerByProxy(proxyUrl string, protocol string, addr string) (c Conn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConnectServerByProxyWithTLS(proxyUrl string, protocol string, addr string, tlsConfig *tls.Config) (c Conn, err error) {
|
func ConnectServerByProxyWithTLS(proxyUrl string, protocol string, addr string, tlsConfig *tls.Config) (c net.Conn, err error) {
|
||||||
c, err = ConnectServerByProxy(proxyUrl, protocol, addr)
|
c, err = ConnectServerByProxy(proxyUrl, protocol, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -18,17 +18,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
|
|
||||||
kcp "github.com/fatedier/kcp-go"
|
kcp "github.com/fatedier/kcp-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
type KcpListener struct {
|
type KcpListener struct {
|
||||||
net.Addr
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
accept chan Conn
|
acceptCh chan net.Conn
|
||||||
closeFlag bool
|
closeFlag bool
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListenKcp(bindAddr string, bindPort int) (l *KcpListener, err error) {
|
func ListenKcp(bindAddr string, bindPort int) (l *KcpListener, err error) {
|
||||||
@ -40,11 +36,9 @@ func ListenKcp(bindAddr string, bindPort int) (l *KcpListener, err error) {
|
|||||||
listener.SetWriteBuffer(4194304)
|
listener.SetWriteBuffer(4194304)
|
||||||
|
|
||||||
l = &KcpListener{
|
l = &KcpListener{
|
||||||
Addr: listener.Addr(),
|
|
||||||
listener: listener,
|
listener: listener,
|
||||||
accept: make(chan Conn),
|
acceptCh: make(chan net.Conn),
|
||||||
closeFlag: false,
|
closeFlag: false,
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -52,7 +46,7 @@ func ListenKcp(bindAddr string, bindPort int) (l *KcpListener, err error) {
|
|||||||
conn, err := listener.AcceptKCP()
|
conn, err := listener.AcceptKCP()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if l.closeFlag {
|
if l.closeFlag {
|
||||||
close(l.accept)
|
close(l.acceptCh)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
@ -64,14 +58,14 @@ func ListenKcp(bindAddr string, bindPort int) (l *KcpListener, err error) {
|
|||||||
conn.SetWindowSize(1024, 1024)
|
conn.SetWindowSize(1024, 1024)
|
||||||
conn.SetACKNoDelay(false)
|
conn.SetACKNoDelay(false)
|
||||||
|
|
||||||
l.accept <- WrapConn(conn)
|
l.acceptCh <- conn
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return l, err
|
return l, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *KcpListener) Accept() (Conn, error) {
|
func (l *KcpListener) Accept() (net.Conn, error) {
|
||||||
conn, ok := <-l.accept
|
conn, ok := <-l.acceptCh
|
||||||
if !ok {
|
if !ok {
|
||||||
return conn, fmt.Errorf("channel for kcp listener closed")
|
return conn, fmt.Errorf("channel for kcp listener closed")
|
||||||
}
|
}
|
||||||
@ -86,6 +80,10 @@ func (l *KcpListener) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *KcpListener) Addr() net.Addr {
|
||||||
|
return l.listener.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
func NewKcpConnFromUdp(conn *net.UDPConn, connected bool, raddr string) (net.Conn, error) {
|
func NewKcpConnFromUdp(conn *net.UDPConn, connected bool, raddr string) (net.Conn, error) {
|
||||||
kcpConn, err := kcp.NewConnEx(1, connected, raddr, nil, 10, 3, conn)
|
kcpConn, err := kcp.NewConnEx(1, connected, raddr, nil, 10, 3, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,65 +19,34 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Listener interface {
|
|
||||||
Accept() (Conn, error)
|
|
||||||
Close() error
|
|
||||||
log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type LogListener struct {
|
|
||||||
l net.Listener
|
|
||||||
net.Listener
|
|
||||||
log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapLogListener(l net.Listener) Listener {
|
|
||||||
return &LogListener{
|
|
||||||
l: l,
|
|
||||||
Listener: l,
|
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (logL *LogListener) Accept() (Conn, error) {
|
|
||||||
c, err := logL.l.Accept()
|
|
||||||
return WrapConn(c), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom listener
|
// Custom listener
|
||||||
type CustomListener struct {
|
type CustomListener struct {
|
||||||
conns chan Conn
|
acceptCh chan net.Conn
|
||||||
closed bool
|
closed bool
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCustomListener() *CustomListener {
|
func NewCustomListener() *CustomListener {
|
||||||
return &CustomListener{
|
return &CustomListener{
|
||||||
conns: make(chan Conn, 64),
|
acceptCh: make(chan net.Conn, 64),
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *CustomListener) Accept() (Conn, error) {
|
func (l *CustomListener) Accept() (net.Conn, error) {
|
||||||
conn, ok := <-l.conns
|
conn, ok := <-l.acceptCh
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("listener closed")
|
return nil, fmt.Errorf("listener closed")
|
||||||
}
|
}
|
||||||
conn.AddLogPrefix(l.GetPrefixStr())
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *CustomListener) PutConn(conn Conn) error {
|
func (l *CustomListener) PutConn(conn net.Conn) error {
|
||||||
err := errors.PanicToError(func() {
|
err := errors.PanicToError(func() {
|
||||||
select {
|
select {
|
||||||
case l.conns <- conn:
|
case l.acceptCh <- conn:
|
||||||
default:
|
default:
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
@ -89,7 +58,7 @@ func (l *CustomListener) Close() error {
|
|||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
defer l.mu.Unlock()
|
||||||
if !l.closed {
|
if !l.closed {
|
||||||
close(l.conns)
|
close(l.acceptCh)
|
||||||
l.closed = true
|
l.closed = true
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
111
utils/net/tcp.go
111
utils/net/tcp.go
@ -1,111 +0,0 @@
|
|||||||
// Copyright 2016 fatedier, fatedier@gmail.com
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package net
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TcpListener struct {
|
|
||||||
net.Addr
|
|
||||||
listener net.Listener
|
|
||||||
accept chan Conn
|
|
||||||
closeFlag bool
|
|
||||||
log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListenTcp(bindAddr string, bindPort int) (l *TcpListener, err error) {
|
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", bindAddr, bindPort))
|
|
||||||
if err != nil {
|
|
||||||
return l, err
|
|
||||||
}
|
|
||||||
listener, err := net.ListenTCP("tcp", tcpAddr)
|
|
||||||
if err != nil {
|
|
||||||
return l, err
|
|
||||||
}
|
|
||||||
|
|
||||||
l = &TcpListener{
|
|
||||||
Addr: listener.Addr(),
|
|
||||||
listener: listener,
|
|
||||||
accept: make(chan Conn),
|
|
||||||
closeFlag: false,
|
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
conn, err := listener.AcceptTCP()
|
|
||||||
if err != nil {
|
|
||||||
if l.closeFlag {
|
|
||||||
close(l.accept)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
c := NewTcpConn(conn)
|
|
||||||
l.accept <- c
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
return l, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait util get one new connection or listener is closed
|
|
||||||
// if listener is closed, err returned.
|
|
||||||
func (l *TcpListener) Accept() (Conn, error) {
|
|
||||||
conn, ok := <-l.accept
|
|
||||||
if !ok {
|
|
||||||
return conn, fmt.Errorf("channel for tcp listener closed")
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *TcpListener) Close() error {
|
|
||||||
if !l.closeFlag {
|
|
||||||
l.closeFlag = true
|
|
||||||
l.listener.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap for TCPConn.
|
|
||||||
type TcpConn struct {
|
|
||||||
net.Conn
|
|
||||||
log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTcpConn(conn net.Conn) (c *TcpConn) {
|
|
||||||
c = &TcpConn{
|
|
||||||
Conn: conn,
|
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConnectTcpServer(addr string) (c Conn, err error) {
|
|
||||||
servertAddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn, err := net.DialTCP("tcp", nil, servertAddr)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c = NewTcpConn(conn)
|
|
||||||
return
|
|
||||||
}
|
|
@ -26,13 +26,13 @@ var (
|
|||||||
FRP_TLS_HEAD_BYTE = 0x17
|
FRP_TLS_HEAD_BYTE = 0x17
|
||||||
)
|
)
|
||||||
|
|
||||||
func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config) (out Conn) {
|
func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config) (out net.Conn) {
|
||||||
c.Write([]byte{byte(FRP_TLS_HEAD_BYTE)})
|
c.Write([]byte{byte(FRP_TLS_HEAD_BYTE)})
|
||||||
out = WrapConn(tls.Client(c, tlsConfig))
|
out = tls.Client(c, tlsConfig)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, timeout time.Duration) (out Conn, err error) {
|
func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, timeout time.Duration) (out net.Conn, err error) {
|
||||||
sc, r := gnet.NewSharedConnSize(c, 2)
|
sc, r := gnet.NewSharedConnSize(c, 2)
|
||||||
buf := make([]byte, 1)
|
buf := make([]byte, 1)
|
||||||
var n int
|
var n int
|
||||||
@ -44,9 +44,9 @@ func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, t
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n == 1 && int(buf[0]) == FRP_TLS_HEAD_BYTE {
|
if n == 1 && int(buf[0]) == FRP_TLS_HEAD_BYTE {
|
||||||
out = WrapConn(tls.Server(c, tlsConfig))
|
out = tls.Server(c, tlsConfig)
|
||||||
} else {
|
} else {
|
||||||
out = WrapConn(sc)
|
out = sc
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
|
|
||||||
"github.com/fatedier/golib/pool"
|
"github.com/fatedier/golib/pool"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,7 +31,6 @@ type UdpPacket struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FakeUdpConn struct {
|
type FakeUdpConn struct {
|
||||||
log.Logger
|
|
||||||
l *UdpListener
|
l *UdpListener
|
||||||
|
|
||||||
localAddr net.Addr
|
localAddr net.Addr
|
||||||
@ -47,7 +44,6 @@ type FakeUdpConn struct {
|
|||||||
|
|
||||||
func NewFakeUdpConn(l *UdpListener, laddr, raddr net.Addr) *FakeUdpConn {
|
func NewFakeUdpConn(l *UdpListener, laddr, raddr net.Addr) *FakeUdpConn {
|
||||||
fc := &FakeUdpConn{
|
fc := &FakeUdpConn{
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
l: l,
|
l: l,
|
||||||
localAddr: laddr,
|
localAddr: laddr,
|
||||||
remoteAddr: raddr,
|
remoteAddr: raddr,
|
||||||
@ -157,15 +153,13 @@ func (c *FakeUdpConn) SetWriteDeadline(t time.Time) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type UdpListener struct {
|
type UdpListener struct {
|
||||||
net.Addr
|
addr net.Addr
|
||||||
accept chan Conn
|
acceptCh chan net.Conn
|
||||||
writeCh chan *UdpPacket
|
writeCh chan *UdpPacket
|
||||||
readConn net.Conn
|
readConn net.Conn
|
||||||
closeFlag bool
|
closeFlag bool
|
||||||
|
|
||||||
fakeConns map[string]*FakeUdpConn
|
fakeConns map[string]*FakeUdpConn
|
||||||
|
|
||||||
log.Logger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListenUDP(bindAddr string, bindPort int) (l *UdpListener, err error) {
|
func ListenUDP(bindAddr string, bindPort int) (l *UdpListener, err error) {
|
||||||
@ -176,11 +170,10 @@ func ListenUDP(bindAddr string, bindPort int) (l *UdpListener, err error) {
|
|||||||
readConn, err := net.ListenUDP("udp", udpAddr)
|
readConn, err := net.ListenUDP("udp", udpAddr)
|
||||||
|
|
||||||
l = &UdpListener{
|
l = &UdpListener{
|
||||||
Addr: udpAddr,
|
addr: udpAddr,
|
||||||
accept: make(chan Conn),
|
acceptCh: make(chan net.Conn),
|
||||||
writeCh: make(chan *UdpPacket, 1000),
|
writeCh: make(chan *UdpPacket, 1000),
|
||||||
fakeConns: make(map[string]*FakeUdpConn),
|
fakeConns: make(map[string]*FakeUdpConn),
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for reading
|
// for reading
|
||||||
@ -189,19 +182,19 @@ func ListenUDP(bindAddr string, bindPort int) (l *UdpListener, err error) {
|
|||||||
buf := pool.GetBuf(1450)
|
buf := pool.GetBuf(1450)
|
||||||
n, remoteAddr, err := readConn.ReadFromUDP(buf)
|
n, remoteAddr, err := readConn.ReadFromUDP(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
close(l.accept)
|
close(l.acceptCh)
|
||||||
close(l.writeCh)
|
close(l.writeCh)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeConn, exist := l.fakeConns[remoteAddr.String()]
|
fakeConn, exist := l.fakeConns[remoteAddr.String()]
|
||||||
if !exist || fakeConn.IsClosed() {
|
if !exist || fakeConn.IsClosed() {
|
||||||
fakeConn = NewFakeUdpConn(l, l.Addr, remoteAddr)
|
fakeConn = NewFakeUdpConn(l, l.Addr(), remoteAddr)
|
||||||
l.fakeConns[remoteAddr.String()] = fakeConn
|
l.fakeConns[remoteAddr.String()] = fakeConn
|
||||||
}
|
}
|
||||||
fakeConn.putPacket(buf[:n])
|
fakeConn.putPacket(buf[:n])
|
||||||
|
|
||||||
l.accept <- fakeConn
|
l.acceptCh <- fakeConn
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -226,7 +219,6 @@ func (l *UdpListener) writeUdpPacket(packet *UdpPacket) (err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if errRet := recover(); errRet != nil {
|
if errRet := recover(); errRet != nil {
|
||||||
err = fmt.Errorf("udp write closed listener")
|
err = fmt.Errorf("udp write closed listener")
|
||||||
l.Info("udp write closed listener")
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
l.writeCh <- packet
|
l.writeCh <- packet
|
||||||
@ -243,8 +235,8 @@ func (l *UdpListener) WriteMsg(buf []byte, remoteAddr *net.UDPAddr) (err error)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *UdpListener) Accept() (Conn, error) {
|
func (l *UdpListener) Accept() (net.Conn, error) {
|
||||||
conn, ok := <-l.accept
|
conn, ok := <-l.acceptCh
|
||||||
if !ok {
|
if !ok {
|
||||||
return conn, fmt.Errorf("channel for udp listener closed")
|
return conn, fmt.Errorf("channel for udp listener closed")
|
||||||
}
|
}
|
||||||
@ -258,3 +250,7 @@ func (l *UdpListener) Close() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *UdpListener) Addr() net.Addr {
|
||||||
|
return l.addr
|
||||||
|
}
|
||||||
|
@ -8,8 +8,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
|
||||||
|
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,10 +20,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type WebsocketListener struct {
|
type WebsocketListener struct {
|
||||||
net.Addr
|
ln net.Listener
|
||||||
ln net.Listener
|
acceptCh chan net.Conn
|
||||||
accept chan Conn
|
|
||||||
log.Logger
|
|
||||||
|
|
||||||
server *http.Server
|
server *http.Server
|
||||||
httpMutex *http.ServeMux
|
httpMutex *http.ServeMux
|
||||||
@ -35,9 +31,7 @@ type WebsocketListener struct {
|
|||||||
// ln: tcp listener for websocket connections
|
// ln: tcp listener for websocket connections
|
||||||
func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
||||||
wl = &WebsocketListener{
|
wl = &WebsocketListener{
|
||||||
Addr: ln.Addr(),
|
acceptCh: make(chan net.Conn),
|
||||||
accept: make(chan Conn),
|
|
||||||
Logger: log.NewPrefixLogger(""),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
muxer := http.NewServeMux()
|
muxer := http.NewServeMux()
|
||||||
@ -46,7 +40,7 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
|||||||
conn := WrapCloseNotifyConn(c, func() {
|
conn := WrapCloseNotifyConn(c, func() {
|
||||||
close(notifyCh)
|
close(notifyCh)
|
||||||
})
|
})
|
||||||
wl.accept <- conn
|
wl.acceptCh <- conn
|
||||||
<-notifyCh
|
<-notifyCh
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@ -68,8 +62,8 @@ func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error)
|
|||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *WebsocketListener) Accept() (Conn, error) {
|
func (p *WebsocketListener) Accept() (net.Conn, error) {
|
||||||
c, ok := <-p.accept
|
c, ok := <-p.acceptCh
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrWebsocketListenerClosed
|
return nil, ErrWebsocketListenerClosed
|
||||||
}
|
}
|
||||||
@ -80,8 +74,12 @@ func (p *WebsocketListener) Close() error {
|
|||||||
return p.server.Close()
|
return p.server.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *WebsocketListener) Addr() net.Addr {
|
||||||
|
return p.ln.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
// addr: domain:port
|
// addr: domain:port
|
||||||
func ConnectWebsocketServer(addr string) (Conn, error) {
|
func ConnectWebsocketServer(addr string) (net.Conn, error) {
|
||||||
addr = "ws://" + addr + FrpWebsocketPath
|
addr = "ws://" + addr + FrpWebsocketPath
|
||||||
uri, err := url.Parse(addr)
|
uri, err := url.Parse(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -101,6 +99,5 @@ func ConnectWebsocketServer(addr string) (Conn, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c := WrapConn(conn)
|
return conn, nil
|
||||||
return c, nil
|
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,10 @@ package vhost
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
|
||||||
|
|
||||||
gnet "github.com/fatedier/golib/net"
|
gnet "github.com/fatedier/golib/net"
|
||||||
"github.com/fatedier/golib/pool"
|
"github.com/fatedier/golib/pool"
|
||||||
)
|
)
|
||||||
@ -48,7 +47,7 @@ type HttpsMuxer struct {
|
|||||||
*VhostMuxer
|
*VhostMuxer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpsMuxer(listener frpNet.Listener, timeout time.Duration) (*HttpsMuxer, error) {
|
func NewHttpsMuxer(listener net.Listener, timeout time.Duration) (*HttpsMuxer, error) {
|
||||||
mux, err := NewVhostMuxer(listener, GetHttpsHostname, nil, nil, timeout)
|
mux, err := NewVhostMuxer(listener, GetHttpsHostname, nil, nil, timeout)
|
||||||
return &HttpsMuxer{mux}, err
|
return &HttpsMuxer{mux}, err
|
||||||
}
|
}
|
||||||
@ -182,7 +181,7 @@ func readHandshake(rd io.Reader) (host string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetHttpsHostname(c frpNet.Conn) (_ frpNet.Conn, _ map[string]string, err error) {
|
func GetHttpsHostname(c net.Conn) (_ net.Conn, _ map[string]string, err error) {
|
||||||
reqInfoMap := make(map[string]string, 0)
|
reqInfoMap := make(map[string]string, 0)
|
||||||
sc, rd := gnet.NewSharedConn(c)
|
sc, rd := gnet.NewSharedConn(c)
|
||||||
host, err := readHandshake(rd)
|
host, err := readHandshake(rd)
|
||||||
@ -191,5 +190,5 @@ func GetHttpsHostname(c frpNet.Conn) (_ frpNet.Conn, _ map[string]string, err er
|
|||||||
}
|
}
|
||||||
reqInfoMap["Host"] = host
|
reqInfoMap["Host"] = host
|
||||||
reqInfoMap["Scheme"] = "https"
|
reqInfoMap["Scheme"] = "https"
|
||||||
return frpNet.WrapConn(sc), reqInfoMap, nil
|
return sc, reqInfoMap, nil
|
||||||
}
|
}
|
||||||
|
@ -13,22 +13,25 @@
|
|||||||
package vhost
|
package vhost
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/utils/log"
|
"github.com/fatedier/frp/utils/log"
|
||||||
frpNet "github.com/fatedier/frp/utils/net"
|
frpNet "github.com/fatedier/frp/utils/net"
|
||||||
|
"github.com/fatedier/frp/utils/xlog"
|
||||||
|
|
||||||
"github.com/fatedier/golib/errors"
|
"github.com/fatedier/golib/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type muxFunc func(frpNet.Conn) (frpNet.Conn, map[string]string, error)
|
type muxFunc func(net.Conn) (net.Conn, map[string]string, error)
|
||||||
type httpAuthFunc func(frpNet.Conn, string, string, string) (bool, error)
|
type httpAuthFunc func(net.Conn, string, string, string) (bool, error)
|
||||||
type hostRewriteFunc func(frpNet.Conn, string) (frpNet.Conn, error)
|
type hostRewriteFunc func(net.Conn, string) (net.Conn, error)
|
||||||
|
|
||||||
type VhostMuxer struct {
|
type VhostMuxer struct {
|
||||||
listener frpNet.Listener
|
listener net.Listener
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
vhostFunc muxFunc
|
vhostFunc muxFunc
|
||||||
authFunc httpAuthFunc
|
authFunc httpAuthFunc
|
||||||
@ -36,7 +39,7 @@ type VhostMuxer struct {
|
|||||||
registryRouter *VhostRouters
|
registryRouter *VhostRouters
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVhostMuxer(listener frpNet.Listener, vhostFunc muxFunc, authFunc httpAuthFunc, rewriteFunc hostRewriteFunc, timeout time.Duration) (mux *VhostMuxer, err error) {
|
func NewVhostMuxer(listener net.Listener, vhostFunc muxFunc, authFunc httpAuthFunc, rewriteFunc hostRewriteFunc, timeout time.Duration) (mux *VhostMuxer, err error) {
|
||||||
mux = &VhostMuxer{
|
mux = &VhostMuxer{
|
||||||
listener: listener,
|
listener: listener,
|
||||||
timeout: timeout,
|
timeout: timeout,
|
||||||
@ -49,7 +52,7 @@ func NewVhostMuxer(listener frpNet.Listener, vhostFunc muxFunc, authFunc httpAut
|
|||||||
return mux, nil
|
return mux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateConnFunc func(remoteAddr string) (frpNet.Conn, error)
|
type CreateConnFunc func(remoteAddr string) (net.Conn, error)
|
||||||
|
|
||||||
// VhostRouteConfig is the params used to match HTTP requests
|
// VhostRouteConfig is the params used to match HTTP requests
|
||||||
type VhostRouteConfig struct {
|
type VhostRouteConfig struct {
|
||||||
@ -65,7 +68,7 @@ type VhostRouteConfig struct {
|
|||||||
|
|
||||||
// listen for a new domain name, if rewriteHost is not empty and rewriteFunc is not nil
|
// listen for a new domain name, if rewriteHost is not empty and rewriteFunc is not nil
|
||||||
// then rewrite the host header to rewriteHost
|
// then rewrite the host header to rewriteHost
|
||||||
func (v *VhostMuxer) Listen(cfg *VhostRouteConfig) (l *Listener, err error) {
|
func (v *VhostMuxer) Listen(ctx context.Context, cfg *VhostRouteConfig) (l *Listener, err error) {
|
||||||
l = &Listener{
|
l = &Listener{
|
||||||
name: cfg.Domain,
|
name: cfg.Domain,
|
||||||
location: cfg.Location,
|
location: cfg.Location,
|
||||||
@ -73,8 +76,8 @@ func (v *VhostMuxer) Listen(cfg *VhostRouteConfig) (l *Listener, err error) {
|
|||||||
userName: cfg.Username,
|
userName: cfg.Username,
|
||||||
passWord: cfg.Password,
|
passWord: cfg.Password,
|
||||||
mux: v,
|
mux: v,
|
||||||
accept: make(chan frpNet.Conn),
|
accept: make(chan net.Conn),
|
||||||
Logger: log.NewPrefixLogger(""),
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
err = v.registryRouter.Add(cfg.Domain, cfg.Location, l)
|
err = v.registryRouter.Add(cfg.Domain, cfg.Location, l)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -123,7 +126,7 @@ func (v *VhostMuxer) run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VhostMuxer) handle(c frpNet.Conn) {
|
func (v *VhostMuxer) handle(c net.Conn) {
|
||||||
if err := c.SetDeadline(time.Now().Add(v.timeout)); err != nil {
|
if err := c.SetDeadline(time.Now().Add(v.timeout)); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
@ -146,13 +149,14 @@ func (v *VhostMuxer) handle(c frpNet.Conn) {
|
|||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
xl := xlog.FromContextSafe(l.ctx)
|
||||||
|
|
||||||
// if authFunc is exist and userName/password is set
|
// if authFunc is exist and userName/password is set
|
||||||
// then verify user access
|
// then verify user access
|
||||||
if l.mux.authFunc != nil && l.userName != "" && l.passWord != "" {
|
if l.mux.authFunc != nil && l.userName != "" && l.passWord != "" {
|
||||||
bAccess, err := l.mux.authFunc(c, l.userName, l.passWord, reqInfoMap["Authorization"])
|
bAccess, err := l.mux.authFunc(c, l.userName, l.passWord, reqInfoMap["Authorization"])
|
||||||
if bAccess == false || err != nil {
|
if bAccess == false || err != nil {
|
||||||
l.Debug("check http Authorization failed")
|
xl.Debug("check http Authorization failed")
|
||||||
res := noAuthResponse()
|
res := noAuthResponse()
|
||||||
res.Write(c)
|
res.Write(c)
|
||||||
c.Close()
|
c.Close()
|
||||||
@ -166,12 +170,12 @@ func (v *VhostMuxer) handle(c frpNet.Conn) {
|
|||||||
}
|
}
|
||||||
c = sConn
|
c = sConn
|
||||||
|
|
||||||
l.Debug("get new http request host [%s] path [%s]", name, path)
|
xl.Debug("get new http request host [%s] path [%s]", name, path)
|
||||||
err = errors.PanicToError(func() {
|
err = errors.PanicToError(func() {
|
||||||
l.accept <- c
|
l.accept <- c
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warn("listener is already closed, ignore this request")
|
xl.Warn("listener is already closed, ignore this request")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,11 +186,12 @@ type Listener struct {
|
|||||||
userName string
|
userName string
|
||||||
passWord string
|
passWord string
|
||||||
mux *VhostMuxer // for closing VhostMuxer
|
mux *VhostMuxer // for closing VhostMuxer
|
||||||
accept chan frpNet.Conn
|
accept chan net.Conn
|
||||||
log.Logger
|
ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Accept() (frpNet.Conn, error) {
|
func (l *Listener) Accept() (net.Conn, error) {
|
||||||
|
xl := xlog.FromContextSafe(l.ctx)
|
||||||
conn, ok := <-l.accept
|
conn, ok := <-l.accept
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Listener closed")
|
return nil, fmt.Errorf("Listener closed")
|
||||||
@ -198,17 +203,13 @@ func (l *Listener) Accept() (frpNet.Conn, error) {
|
|||||||
if l.mux.rewriteFunc != nil {
|
if l.mux.rewriteFunc != nil {
|
||||||
sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost)
|
sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Warn("host header rewrite failed: %v", err)
|
xl.Warn("host header rewrite failed: %v", err)
|
||||||
return nil, fmt.Errorf("host header rewrite failed")
|
return nil, fmt.Errorf("host header rewrite failed")
|
||||||
}
|
}
|
||||||
l.Debug("rewrite host to [%s] success", l.rewriteHost)
|
xl.Debug("rewrite host to [%s] success", l.rewriteHost)
|
||||||
conn = sConn
|
conn = sConn
|
||||||
}
|
}
|
||||||
|
return frpNet.NewContextConn(conn, l.ctx), nil
|
||||||
for _, prefix := range l.GetAllPrefix() {
|
|
||||||
conn.AddLogPrefix(prefix)
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) Close() error {
|
func (l *Listener) Close() error {
|
||||||
@ -220,3 +221,7 @@ func (l *Listener) Close() error {
|
|||||||
func (l *Listener) Name() string {
|
func (l *Listener) Name() string {
|
||||||
return l.name
|
return l.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Listener) Addr() net.Addr {
|
||||||
|
return (*net.TCPAddr)(nil)
|
||||||
|
}
|
||||||
|
42
utils/xlog/ctx.go
Normal file
42
utils/xlog/ctx.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2019 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package xlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type key int
|
||||||
|
|
||||||
|
const (
|
||||||
|
xlogKey key = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewContext(ctx context.Context, xl *Logger) context.Context {
|
||||||
|
return context.WithValue(ctx, xlogKey, xl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromContext(ctx context.Context) (xl *Logger, ok bool) {
|
||||||
|
xl, ok = ctx.Value(xlogKey).(*Logger)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromContextSafe(ctx context.Context) *Logger {
|
||||||
|
xl, ok := ctx.Value(xlogKey).(*Logger)
|
||||||
|
if !ok {
|
||||||
|
xl = New()
|
||||||
|
}
|
||||||
|
return xl
|
||||||
|
}
|
73
utils/xlog/xlog.go
Normal file
73
utils/xlog/xlog.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// Copyright 2019 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package xlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/fatedier/frp/utils/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Logger is not thread safety for operations on prefix
|
||||||
|
type Logger struct {
|
||||||
|
prefixes []string
|
||||||
|
|
||||||
|
prefixString string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Logger {
|
||||||
|
return &Logger{
|
||||||
|
prefixes: make([]string, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) ResetPrefixes() (old []string) {
|
||||||
|
old = l.prefixes
|
||||||
|
l.prefixes = make([]string, 0)
|
||||||
|
l.prefixString = ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) AppendPrefix(prefix string) *Logger {
|
||||||
|
l.prefixes = append(l.prefixes, prefix)
|
||||||
|
l.prefixString += "[" + prefix + "] "
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Spawn() *Logger {
|
||||||
|
nl := New()
|
||||||
|
for _, v := range l.prefixes {
|
||||||
|
nl.AppendPrefix(v)
|
||||||
|
}
|
||||||
|
return nl
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Error(format string, v ...interface{}) {
|
||||||
|
log.Log.Error(l.prefixString+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Warn(format string, v ...interface{}) {
|
||||||
|
log.Log.Warn(l.prefixString+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Info(format string, v ...interface{}) {
|
||||||
|
log.Log.Info(l.prefixString+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Debug(format string, v ...interface{}) {
|
||||||
|
log.Log.Debug(l.prefixString+format, v...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Logger) Trace(format string, v ...interface{}) {
|
||||||
|
log.Log.Trace(l.prefixString+format, v...)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user