lint by golangci-lint (#3080)

This commit is contained in:
fatedier 2022-08-29 01:02:53 +08:00 committed by GitHub
parent f4e4fbea62
commit 9d077b02cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 947 additions and 1331 deletions

View File

@ -2,14 +2,16 @@ version: 2
jobs: jobs:
go-version-latest: go-version-latest:
docker: docker:
- image: cimg/go:1.18-node - image: cimg/go:1.19-node
resource_class: large
steps: steps:
- checkout - checkout
- run: make - run: make
- run: make alltest - run: make alltest
go-version-last: go-version-last:
docker: docker:
- image: cimg/go:1.17-node - image: cimg/go:1.18-node
resource_class: large
steps: steps:
- checkout - checkout
- run: make - run: make

41
.github/workflows/golangci-lint.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: golangci-lint
on:
push:
branches:
- master
- dev
pull_request:
permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
pull-requests: read
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
version: v1.49.0
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true
# Optional: if set to true then the all caching functionality will be complete disabled,
# takes precedence over all other caching options.
# skip-cache: true
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true

View File

@ -15,7 +15,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.18 go-version: 1.19
- run: | - run: |
# https://github.com/actions/setup-go/issues/107 # https://github.com/actions/setup-go/issues/107

141
.golangci.yml Normal file
View File

@ -0,0 +1,141 @@
service:
# When updating this, also update the version stored in docker/build-tools/Dockerfile in the istio/tools repo.
golangci-lint-version: 1.49.x # use the fixed version to not introduce new linters unexpectedly
run:
concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m
deadline: 20m
build-tags:
- integ
- integfuzz
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- genfiles$
- vendor$
- bin$
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
skip-files:
- ".*\\.pb\\.go"
- ".*\\.gen\\.go"
linters:
disable-all: true
enable:
- unused
- errcheck
- exportloopref
- gocritic
- gofumpt
- goimports
- revive
- gosimple
- govet
- ineffassign
- lll
- misspell
- staticcheck
- stylecheck
- typecheck
- unconvert
- unparam
- gci
- bodyclose
- gosec
- asciicheck
- prealloc
- predeclared
- makezero
fast: false
linters-settings:
errcheck:
# report about not checking of errors in type assetions: `a := b.(MyStruct)`;
# default is false: such cases aren't reported by default.
check-type-assertions: false
# report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
# default is false: such cases aren't reported by default.
check-blank: false
govet:
# report about shadowed variables
check-shadowing: false
maligned:
# print struct with more effective memory layout or not, false by default
suggest-new: true
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
ignore-words:
- cancelled
- marshalled
lll:
# max line length, lines longer will be reported. Default is 120.
# '\t' is counted as 1 character by default, and can be changed with the tab-width option
line-length: 160
# tab width in spaces. Default to 1.
tab-width: 1
gocritic:
disabled-checks:
- exitAfterDefer
unused:
check-exported: false
unparam:
# Inspect exported functions, default is false. Set to true if no external program/library imports your code.
# XXX: if you enable this setting, unparam will report a lot of false-positives in text editors:
# if it's called for subdir of a project it can't find external interfaces. All text editor integrations
# with golangci-lint call it on a directory with the changed file.
check-exported: false
gci:
sections:
- standard
- default
- prefix(github.com/fatedier/frp/)
gosec:
severity: "low"
confidence: "low"
excludes:
- G102
- G112
- G306
- G401
- G402
- G404
- G501
issues:
# List of regexps of issue texts to exclude, empty list by default.
# But independently from this option we use default exclude patterns,
# it can be disabled by `exclude-use-default: false`. To list all
# excluded by default patterns execute `golangci-lint run --help`
# exclude:
# - composite literal uses unkeyed fields
exclude-rules:
# Exclude some linters from running on test files.
- path: _test\.go$|^tests/|^samples/
linters:
- errcheck
- maligned
# Independently from option `exclude` we use default exclude patterns,
# it can be disabled by this option. To list all
# excluded by default patterns execute `golangci-lint run --help`.
# Default value for this option is true.
exclude-use-default: true
# Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same-issues: 0

View File

@ -20,10 +20,10 @@ import (
"net/http/pprof" "net/http/pprof"
"time" "time"
"github.com/gorilla/mux"
"github.com/fatedier/frp/assets" "github.com/fatedier/frp/assets"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/gorilla/mux"
) )
var ( var (
@ -77,6 +77,8 @@ func (svr *Service) RunAdminServer(address string) (err error) {
return err return err
} }
go server.Serve(ln) go func() {
_ = server.Serve(ln)
}()
return return
} }

View File

@ -49,7 +49,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
log.Info("api response [/api/reload], code [%d]", res.Code) log.Info("api response [/api/reload], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
@ -68,7 +68,6 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
return return
} }
log.Info("success reload conf") log.Info("success reload conf")
return
} }
type StatusResp struct { type StatusResp struct {
@ -173,7 +172,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
defer func() { defer func() {
log.Info("Http response [/api/status]") log.Info("Http response [/api/status]")
buf, _ = json.Marshal(&res) buf, _ = json.Marshal(&res)
w.Write(buf) _, _ = w.Write(buf)
}() }()
ps := svr.ctl.pm.GetAllProxyStatus() ps := svr.ctl.pm.GetAllProxyStatus()
@ -202,7 +201,6 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
sort.Sort(ByProxyStatusResp(res.STCP)) sort.Sort(ByProxyStatusResp(res.STCP))
sort.Sort(ByProxyStatusResp(res.XTCP)) sort.Sort(ByProxyStatusResp(res.XTCP))
sort.Sort(ByProxyStatusResp(res.SUDP)) sort.Sort(ByProxyStatusResp(res.SUDP))
return
} }
// GET api/config // GET api/config
@ -214,7 +212,7 @@ func (svr *Service) apiGetConfig(w http.ResponseWriter, r *http.Request) {
log.Info("Http get response [/api/config], code [%d]", res.Code) log.Info("Http get response [/api/config], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
@ -254,7 +252,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
log.Info("Http put response [/api/config], code [%d]", res.Code) log.Info("Http put response [/api/config], code [%d]", res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
@ -315,7 +313,7 @@ func (svr *Service) apiPutConfig(w http.ResponseWriter, r *http.Request) {
} }
content = strings.Join(newRows, "\n") content = strings.Join(newRows, "\n")
err = os.WriteFile(svr.cfgFile, []byte(content), 0644) err = os.WriteFile(svr.cfgFile, []byte(content), 0o644)
if err != nil { if err != nil {
res.Code = 500 res.Code = 500
res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err) res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)

View File

@ -21,9 +21,13 @@ import (
"net" "net"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/fatedier/golib/control/shutdown"
"github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux"
"github.com/fatedier/frp/client/proxy" "github.com/fatedier/frp/client/proxy"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
@ -31,11 +35,6 @@ import (
"github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/transport"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/control/shutdown"
"github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux"
) )
type Control struct { type Control struct {
@ -79,8 +78,6 @@ type Control struct {
// The UDP port that the server is listening on // The UDP port that the server is listening on
serverUDPPort int serverUDPPort int
mu sync.RWMutex
xl *xlog.Logger xl *xlog.Logger
// service context // service context
@ -95,8 +92,8 @@ func NewControl(ctx context.Context, runID string, conn net.Conn, session *fmux.
pxyCfgs map[string]config.ProxyConf, pxyCfgs map[string]config.ProxyConf,
visitorCfgs map[string]config.VisitorConf, visitorCfgs map[string]config.VisitorConf,
serverUDPPort int, serverUDPPort int,
authSetter auth.Setter) *Control { authSetter auth.Setter,
) *Control {
// new xlog instance // new xlog instance
ctl := &Control{ ctl := &Control{
runID: runID, runID: runID,
@ -131,7 +128,6 @@ func (ctl *Control) Run() {
// start all visitors // start all visitors
go ctl.vm.Run() go ctl.vm.Run()
return
} }
func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) { func (ctl *Control) HandleReqWorkConn(inMsg *msg.ReqWorkConn) {
@ -400,8 +396,7 @@ func (ctl *Control) worker() {
go ctl.reader() go ctl.reader()
go ctl.writer() go ctl.writer()
select { <-ctl.closedCh
case <-ctl.closedCh:
// close related channels and wait until other goroutines done // close related channels and wait until other goroutines done
close(ctl.readCh) close(ctl.readCh)
ctl.readerShutdown.WaitDone() ctl.readerShutdown.WaitDone()
@ -417,8 +412,6 @@ func (ctl *Control) worker() {
if ctl.session != nil { if ctl.session != nil {
ctl.session.Close() ctl.session.Close()
} }
return
}
} }
func (ctl *Control) ReloadConf(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) error { func (ctl *Control) ReloadConf(pxyCfgs map[string]config.ProxyConf, visitorCfgs map[string]config.VisitorConf) error {

View File

@ -6,9 +6,7 @@ import (
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
) )
var ( var ErrPayloadType = errors.New("error payload type")
ErrPayloadType = errors.New("error payload type")
)
type Handler func(payload interface{}) error type Handler func(payload interface{}) error

View File

@ -26,9 +26,7 @@ import (
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
) )
var ( var ErrHealthCheckType = errors.New("error health check type")
ErrHealthCheckType = errors.New("error health check type")
)
type Monitor struct { type Monitor struct {
checkType string checkType string
@ -54,8 +52,8 @@ type Monitor struct {
func NewMonitor(ctx context.Context, checkType string, func NewMonitor(ctx context.Context, checkType string,
intervalS int, timeoutS int, maxFailedTimes int, intervalS int, timeoutS int, maxFailedTimes int,
addr string, url string, addr string, url string,
statusNormalFn func(), statusFailedFn func()) *Monitor { statusNormalFn func(), statusFailedFn func(),
) *Monitor {
if intervalS <= 0 { if intervalS <= 0 {
intervalS = 10 intervalS = 10
} }
@ -152,7 +150,7 @@ func (monitor *Monitor) doTCPCheck(ctx context.Context) error {
} }
func (monitor *Monitor) doHTTPCheck(ctx context.Context) error { func (monitor *Monitor) doHTTPCheck(ctx context.Context) error {
req, err := http.NewRequest("GET", monitor.url, nil) req, err := http.NewRequestWithContext(ctx, "GET", monitor.url, nil)
if err != nil { if err != nil {
return err return err
} }
@ -161,7 +159,7 @@ func (monitor *Monitor) doHTTPCheck(ctx context.Context) error {
return err return err
} }
defer resp.Body.Close() defer resp.Body.Close()
io.Copy(io.Discard, resp.Body) _, _ = io.Copy(io.Discard, resp.Body)
if resp.StatusCode/100 != 2 { if resp.StatusCode/100 != 2 {
return fmt.Errorf("do http health check, StatusCode is [%d] not 2xx", resp.StatusCode) return fmt.Errorf("do http health check, StatusCode is [%d] not 2xx", resp.StatusCode)

View File

@ -24,14 +24,6 @@ import (
"sync" "sync"
"time" "time"
"github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg"
plugin "github.com/fatedier/frp/pkg/plugin/client"
"github.com/fatedier/frp/pkg/proto/udp"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
libdial "github.com/fatedier/golib/net/dial" libdial "github.com/fatedier/golib/net/dial"
@ -39,6 +31,14 @@ import (
fmux "github.com/hashicorp/yamux" fmux "github.com/hashicorp/yamux"
pp "github.com/pires/go-proxyproto" pp "github.com/pires/go-proxyproto"
"golang.org/x/time/rate" "golang.org/x/time/rate"
"github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg"
plugin "github.com/fatedier/frp/pkg/plugin/client"
"github.com/fatedier/frp/pkg/proto/udp"
"github.com/fatedier/frp/pkg/util/limit"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog"
) )
// Proxy defines how to handle work connections for different proxy type. // Proxy defines how to handle work connections for different proxy type.
@ -322,7 +322,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
// Wait for client address at most 5 seconds. // Wait for client address at most 5 seconds.
var natHoleRespMsg msg.NatHoleResp var natHoleRespMsg msg.NatHoleResp
clientConn.SetReadDeadline(time.Now().Add(5 * time.Second)) _ = clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
buf := pool.GetBuf(1024) buf := pool.GetBuf(1024)
n, err := clientConn.Read(buf) n, err := clientConn.Read(buf)
@ -335,8 +335,8 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
xl.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 != "" {
xl.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error) xl.Error("natHoleRespMsg get error info: %s", natHoleRespMsg.Error)
@ -357,10 +357,13 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
xl.Error("get natHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr) xl.Error("get natHoleResp visitor address error: %v", natHoleRespMsg.VisitorAddr)
return return
} }
pxy.sendDetectMsg(host, int(port), laddr, []byte(natHoleRespMsg.Sid)) _ = pxy.sendDetectMsg(host, int(port), laddr, []byte(natHoleRespMsg.Sid))
xl.Trace("send all detect msg done") xl.Trace("send all detect msg done")
msg.WriteMsg(conn, &msg.NatHoleClientDetectOK{}) if err := msg.WriteMsg(conn, &msg.NatHoleClientDetectOK{}); err != nil {
xl.Error("write message error: %v", err)
return
}
// 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)
@ -370,7 +373,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
} }
defer lConn.Close() defer lConn.Close()
lConn.SetReadDeadline(time.Now().Add(8 * time.Second)) _ = lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
sidBuf := pool.GetBuf(1024) sidBuf := pool.GetBuf(1024)
var uAddr *net.UDPAddr var uAddr *net.UDPAddr
n, uAddr, err = lConn.ReadFromUDP(sidBuf) n, uAddr, err = lConn.ReadFromUDP(sidBuf)
@ -378,7 +381,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
xl.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 {
xl.Warn("incorrect sid from visitor") xl.Warn("incorrect sid from visitor")
return return
@ -386,7 +389,10 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
pool.PutBuf(sidBuf) pool.PutBuf(sidBuf)
xl.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) if _, err := lConn.WriteToUDP(sidBuf[:n], uAddr); err != nil {
xl.Error("write uaddr error: %v", err)
return
}
kcpConn, err := frpNet.NewKCPConnFromUDP(lConn, false, uAddr.String()) kcpConn, err := frpNet.NewKCPConnFromUDP(lConn, false, uAddr.String())
if err != nil { if err != nil {
@ -427,9 +433,10 @@ func (pxy *XTCPProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, c
// uConn := ipv4.NewConn(tConn) // uConn := ipv4.NewConn(tConn)
// uConn.SetTTL(3) // uConn.SetTTL(3)
tConn.Write(content) if _, err := tConn.Write(content); err != nil {
tConn.Close() return err
return nil }
return tConn.Close()
} }
// UDP // UDP
@ -539,7 +546,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
} }
} }
} }
heartbeatFn := func(conn net.Conn, sendCh chan msg.Message) { heartbeatFn := func(sendCh chan msg.Message) {
var errRet error var errRet error
for { for {
time.Sleep(time.Duration(30) * time.Second) time.Sleep(time.Duration(30) * time.Second)
@ -554,7 +561,7 @@ func (pxy *UDPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
go workConnSenderFn(pxy.workConn, pxy.sendCh) go workConnSenderFn(pxy.workConn, pxy.sendCh)
go workConnReaderFn(pxy.workConn, pxy.readCh) go workConnReaderFn(pxy.workConn, pxy.readCh)
go heartbeatFn(pxy.workConn, pxy.sendCh) go heartbeatFn(pxy.sendCh)
udp.Forwarder(pxy.localAddr, pxy.readCh, pxy.sendCh, int(pxy.clientCfg.UDPPacketSize)) udp.Forwarder(pxy.localAddr, pxy.readCh, pxy.sendCh, int(pxy.clientCfg.UDPPacketSize))
} }
@ -685,7 +692,7 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
} }
} }
heartbeatFn := func(conn net.Conn, sendCh chan msg.Message) { heartbeatFn := func(sendCh chan msg.Message) {
ticker := time.NewTicker(30 * time.Second) ticker := time.NewTicker(30 * time.Second)
defer func() { defer func() {
ticker.Stop() ticker.Stop()
@ -711,14 +718,15 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
go workConnSenderFn(workConn, sendCh) go workConnSenderFn(workConn, sendCh)
go workConnReaderFn(workConn, readCh) go workConnReaderFn(workConn, readCh)
go heartbeatFn(workConn, sendCh) go heartbeatFn(sendCh)
udp.Forwarder(pxy.localAddr, readCh, sendCh, int(pxy.clientCfg.UDPPacketSize)) udp.Forwarder(pxy.localAddr, readCh, sendCh, int(pxy.clientCfg.UDPPacketSize))
} }
// Common handler for tcp work connections. // Common handler for tcp work connections.
func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin, func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf, proxyPlugin plugin.Plugin,
baseInfo *config.BaseProxyConf, limiter *rate.Limiter, workConn net.Conn, encKey []byte, m *msg.StartWorkConn) { baseInfo *config.BaseProxyConf, limiter *rate.Limiter, workConn net.Conn, encKey []byte, m *msg.StartWorkConn,
) {
xl := xlog.FromContextSafe(ctx) xl := xlog.FromContextSafe(ctx)
var ( var (
remote io.ReadWriteCloser remote io.ReadWriteCloser
@ -773,7 +781,7 @@ func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf
} }
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
h.WriteTo(buf) _, _ = h.WriteTo(buf)
extraInfo = buf.Bytes() extraInfo = buf.Bytes()
} }
} }
@ -800,7 +808,11 @@ func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf
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 {
localConn.Write(extraInfo) if _, err := localConn.Write(extraInfo); err != nil {
workConn.Close()
xl.Error("write extraInfo to local conn error: %v", err)
return
}
} }
frpIo.Join(localConn, remote) frpIo.Join(localConn, remote)

View File

@ -6,12 +6,12 @@ import (
"net" "net"
"sync" "sync"
"github.com/fatedier/golib/errors"
"github.com/fatedier/frp/client/event" "github.com/fatedier/frp/client/event"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/errors"
) )
type Manager struct { type Manager struct {
@ -113,11 +113,9 @@ func (pm *Manager) Reload(pxyCfgs map[string]config.ProxyConf) {
cfg, ok := pxyCfgs[name] cfg, ok := pxyCfgs[name]
if !ok { if !ok {
del = true del = true
} else { } else if !pxy.Cfg.Compare(cfg) {
if !pxy.Cfg.Compare(cfg) {
del = true del = true
} }
}
if del { if del {
delPxyNames = append(delPxyNames, name) delPxyNames = append(delPxyNames, name)

View File

@ -8,13 +8,13 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/fatedier/golib/errors"
"github.com/fatedier/frp/client/event" "github.com/fatedier/frp/client/event"
"github.com/fatedier/frp/client/health" "github.com/fatedier/frp/client/health"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/errors"
) )
const ( const (
@ -27,7 +27,7 @@ const (
) )
var ( var (
statusCheckInterval time.Duration = 3 * time.Second statusCheckInterval = 3 * time.Second
waitResponseTimeout = 20 * time.Second waitResponseTimeout = 20 * time.Second
startErrTimeout = 30 * time.Second startErrTimeout = 30 * time.Second
) )
@ -145,7 +145,7 @@ func (pw *Wrapper) Stop() {
} }
func (pw *Wrapper) close() { func (pw *Wrapper) close() {
pw.handler(&event.CloseProxyPayload{ _ = pw.handler(&event.CloseProxyPayload{
CloseProxyMsg: &msg.CloseProxy{ CloseProxyMsg: &msg.CloseProxy{
ProxyName: pw.Name, ProxyName: pw.Name,
}, },
@ -174,7 +174,7 @@ func (pw *Wrapper) checkWorker() {
var newProxyMsg msg.NewProxy var newProxyMsg msg.NewProxy
pw.Cfg.MarshalToMsg(&newProxyMsg) pw.Cfg.MarshalToMsg(&newProxyMsg)
pw.lastSendStartMsg = now pw.lastSendStartMsg = now
pw.handler(&event.StartProxyPayload{ _ = pw.handler(&event.StartProxyPayload{
NewProxyMsg: &newProxyMsg, NewProxyMsg: &newProxyMsg,
}) })
} }
@ -201,7 +201,7 @@ func (pw *Wrapper) checkWorker() {
func (pw *Wrapper) statusNormalCallback() { func (pw *Wrapper) statusNormalCallback() {
xl := pw.xl xl := pw.xl
atomic.StoreUint32(&pw.health, 0) atomic.StoreUint32(&pw.health, 0)
errors.PanicToError(func() { _ = errors.PanicToError(func() {
select { select {
case pw.healthNotifyCh <- struct{}{}: case pw.healthNotifyCh <- struct{}{}:
default: default:
@ -213,7 +213,7 @@ func (pw *Wrapper) statusNormalCallback() {
func (pw *Wrapper) statusFailedCallback() { func (pw *Wrapper) statusFailedCallback() {
xl := pw.xl xl := pw.xl
atomic.StoreUint32(&pw.health, 1) atomic.StoreUint32(&pw.health, 1)
errors.PanicToError(func() { _ = errors.PanicToError(func() {
select { select {
case pw.healthNotifyCh <- struct{}{}: case pw.healthNotifyCh <- struct{}{}:
default: default:

View File

@ -28,6 +28,10 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux"
"github.com/fatedier/frp/assets" "github.com/fatedier/frp/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
@ -38,10 +42,6 @@ import (
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/crypto"
libdial "github.com/fatedier/golib/net/dial"
fmux "github.com/hashicorp/yamux"
) )
func init() { func init() {
@ -81,8 +81,12 @@ type Service struct {
cancel context.CancelFunc cancel context.CancelFunc
} }
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()) ctx, cancel := context.WithCancel(context.Background())
svr = &Service{ svr = &Service{
authSetter: auth.NewAuthSetter(cfg.ClientConfig), authSetter: auth.NewAuthSetter(cfg.ClientConfig),
@ -208,7 +212,7 @@ func (svr *Service) keepControllerWorking() {
xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime) xl.Warn("reconnect to server error: %v, wait %v for another retry", err, delayTime)
util.RandomSleep(delayTime, 0.9, 1.1) util.RandomSleep(delayTime, 0.9, 1.1)
delayTime = delayTime * 2 delayTime *= 2
if delayTime > maxDelayTime { if delayTime > maxDelayTime {
delayTime = maxDelayTime delayTime = maxDelayTime
} }
@ -333,11 +337,11 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
} }
var loginRespMsg msg.LoginResp var loginRespMsg msg.LoginResp
conn.SetReadDeadline(time.Now().Add(10 * time.Second)) _ = conn.SetReadDeadline(time.Now().Add(10 * time.Second))
if err = msg.ReadMsgInto(conn, &loginRespMsg); err != nil { if err = msg.ReadMsgInto(conn, &loginRespMsg); err != nil {
return return
} }
conn.SetReadDeadline(time.Time{}) _ = conn.SetReadDeadline(time.Time{})
if loginRespMsg.Error != "" { if loginRespMsg.Error != "" {
err = fmt.Errorf("%s", loginRespMsg.Error) err = fmt.Errorf("%s", loginRespMsg.Error)

View File

@ -24,17 +24,17 @@ import (
"sync" "sync"
"time" "time"
"github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
fmux "github.com/hashicorp/yamux"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/proto/udp" "github.com/fatedier/frp/pkg/proto/udp"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
fmux "github.com/hashicorp/yamux"
) )
// Visitor is used for forward traffics from local port tot remote service. // Visitor is used for forward traffics from local port tot remote service.
@ -73,7 +73,6 @@ func NewVisitor(ctx context.Context, ctl *Control, cfg config.VisitorConf) (visi
type BaseVisitor struct { type BaseVisitor struct {
ctl *Control ctl *Control
l net.Listener l net.Listener
closed bool
mu sync.RWMutex mu sync.RWMutex
ctx context.Context ctx context.Context
@ -138,13 +137,13 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
} }
var newVisitorConnRespMsg msg.NewVisitorConnResp var newVisitorConnRespMsg msg.NewVisitorConnResp
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 {
xl.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 != "" {
xl.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error) xl.Warn("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
@ -239,7 +238,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
// Wait for client address at most 10 seconds. // Wait for client address at most 10 seconds.
var natHoleRespMsg msg.NatHoleResp var natHoleRespMsg msg.NatHoleResp
visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second)) _ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
buf := pool.GetBuf(1024) buf := pool.GetBuf(1024)
n, err := visitorConn.Read(buf) n, err := visitorConn.Read(buf)
if err != nil { if err != nil {
@ -252,7 +251,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
xl.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 != "" {
@ -279,17 +278,20 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
} }
defer lConn.Close() defer lConn.Close()
lConn.Write([]byte(natHoleRespMsg.Sid)) if _, err := lConn.Write([]byte(natHoleRespMsg.Sid)); err != nil {
xl.Error("write sid error: %v", err)
return
}
// read ack sid from client // read ack sid from client
sidBuf := pool.GetBuf(1024) sidBuf := pool.GetBuf(1024)
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 {
xl.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 {
xl.Warn("incorrect sid from client") xl.Warn("incorrect sid from client")
return return
@ -411,7 +413,6 @@ func (sv *SUDPVisitor) dispatcher() {
default: default:
} }
} }
} }
func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) { func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
@ -437,13 +438,13 @@ func (sv *SUDPVisitor) worker(workConn net.Conn, firstPacket *msg.UDPPacket) {
) )
// frpc will send heartbeat in workConn to frpc visitor for keeping alive // frpc will send heartbeat in workConn to frpc visitor for keeping alive
conn.SetReadDeadline(time.Now().Add(60 * time.Second)) _ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil { if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
xl.Warn("read from workconn for user udp conn error: %v", errRet) xl.Warn("read from workconn for user udp conn error: %v", errRet)
return return
} }
conn.SetReadDeadline(time.Time{}) _ = conn.SetReadDeadline(time.Time{})
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.Ping: case *msg.Ping:
xl.Debug("frpc visitor get ping message from frpc") xl.Debug("frpc visitor get ping message from frpc")
@ -523,12 +524,12 @@ func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
} }
var newVisitorConnRespMsg msg.NewVisitorConnResp var newVisitorConnRespMsg msg.NewVisitorConnResp
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 {
return nil, fmt.Errorf("frpc read newVisitorConnRespMsg error: %v", err) return nil, fmt.Errorf("frpc read newVisitorConnRespMsg error: %v", err)
} }
visitorConn.SetReadDeadline(time.Time{}) _ = visitorConn.SetReadDeadline(time.Time{})
if newVisitorConnRespMsg.Error != "" { if newVisitorConnRespMsg.Error != "" {
return nil, fmt.Errorf("start new visitor connection error: %s", newVisitorConnRespMsg.Error) return nil, fmt.Errorf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)

View File

@ -65,7 +65,7 @@ func (vm *VisitorManager) Run() {
name := cfg.GetBaseInfo().ProxyName name := cfg.GetBaseInfo().ProxyName
if _, exist := vm.visitors[name]; !exist { if _, exist := vm.visitors[name]; !exist {
xl.Info("try to start visitor [%s]", name) xl.Info("try to start visitor [%s]", name)
vm.startVisitor(cfg) _ = vm.startVisitor(cfg)
} }
} }
vm.mu.Unlock() vm.mu.Unlock()
@ -99,11 +99,9 @@ func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
cfg, ok := cfgs[name] cfg, ok := cfgs[name]
if !ok { if !ok {
del = true del = true
} else { } else if !oldCfg.Compare(cfg) {
if !oldCfg.Compare(cfg) {
del = true del = true
} }
}
if del { if del {
delNames = append(delNames, name) delNames = append(delNames, name)
@ -123,13 +121,12 @@ func (vm *VisitorManager) Reload(cfgs map[string]config.VisitorConf) {
if _, ok := vm.cfgs[name]; !ok { if _, ok := vm.cfgs[name]; !ok {
vm.cfgs[name] = cfg vm.cfgs[name] = cfg
addNames = append(addNames, name) addNames = append(addNames, name)
vm.startVisitor(cfg) _ = vm.startVisitor(cfg)
} }
} }
if len(addNames) > 0 { if len(addNames) > 0 {
xl.Info("visitor added: %v", addNames) xl.Info("visitor added: %v", addNames)
} }
return
} }
func (vm *VisitorManager) Close() { func (vm *VisitorManager) Close() {

View File

@ -19,10 +19,10 @@ import (
"os" "os"
"strings" "strings"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/spf13/cobra"
) )
func init() { func init() {

View File

@ -22,9 +22,9 @@ import (
"os" "os"
"strings" "strings"
"github.com/fatedier/frp/pkg/config"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
) )
func init() { func init() {

View File

@ -26,13 +26,13 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/spf13/cobra"
"github.com/fatedier/frp/client" "github.com/fatedier/frp/client"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
"github.com/spf13/cobra"
) )
const ( const (
@ -107,7 +107,7 @@ var rootCmd = &cobra.Command{
// Note that it's only designed for testing. It's not guaranteed to be stable. // Note that it's only designed for testing. It's not guaranteed to be stable.
if cfgDir != "" { if cfgDir != "" {
var wg sync.WaitGroup var wg sync.WaitGroup
filepath.WalkDir(cfgDir, func(path string, d fs.DirEntry, err error) error { _ = filepath.WalkDir(cfgDir, func(path string, d fs.DirEntry, err error) error {
if err != nil { if err != nil {
return nil return nil
} }
@ -183,7 +183,7 @@ func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
cfg.Complete() cfg.Complete()
if err = cfg.Validate(); err != nil { if err = cfg.Validate(); err != nil {
err = fmt.Errorf("Parse config error: %v", err) err = fmt.Errorf("parse config error: %v", err)
return return
} }
return return
@ -203,7 +203,6 @@ func startService(
visitorCfgs map[string]config.VisitorConf, visitorCfgs map[string]config.VisitorConf,
cfgFile string, cfgFile string,
) (err error) { ) (err error) {
log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel, log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel,
cfg.LogMaxDays, cfg.DisableLogColor) cfg.LogMaxDays, cfg.DisableLogColor)

View File

@ -23,11 +23,11 @@ import (
"os" "os"
"strings" "strings"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/pkg/config"
"github.com/rodaine/table" "github.com/rodaine/table"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fatedier/frp/client"
"github.com/fatedier/frp/pkg/config"
) )
func init() { func init() {

View File

@ -18,10 +18,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/spf13/cobra"
) )
func init() { func init() {

View File

@ -18,10 +18,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/spf13/cobra"
) )
func init() { func init() {

View File

@ -18,10 +18,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/spf13/cobra"
) )
func init() { func init() {

View File

@ -18,9 +18,9 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/fatedier/frp/pkg/config"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
) )
func init() { func init() {

View File

@ -18,10 +18,10 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/spf13/cobra"
) )
func init() { func init() {

View File

@ -18,14 +18,14 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
"github.com/fatedier/frp/server" "github.com/fatedier/frp/server"
"github.com/spf13/cobra"
) )
const ( const (
@ -50,16 +50,13 @@ var (
dashboardUser string dashboardUser string
dashboardPwd string dashboardPwd string
enablePrometheus bool enablePrometheus bool
assetsDir string
logFile string logFile string
logLevel string logLevel string
logMaxDays int64 logMaxDays int64
disableLogColor bool disableLogColor bool
token string token string
subDomainHost string subDomainHost string
tcpMux bool
allowPorts string allowPorts string
maxPoolCount int64
maxPortsPerClient int64 maxPortsPerClient int64
tlsOnly bool tlsOnly bool
dashboardTLSMode bool dashboardTLSMode bool
@ -151,7 +148,7 @@ func parseServerCommonCfg(fileType int, source []byte) (cfg config.ServerCommonC
cfg.Complete() cfg.Complete()
err = cfg.Validate() err = cfg.Validate()
if err != nil { if err != nil {
err = fmt.Errorf("Parse config error: %v", err) err = fmt.Errorf("parse config error: %v", err)
return return
} }
return return
@ -189,7 +186,7 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
// e.g. 1000-2000,2001,2002,3000-4000 // e.g. 1000-2000,2001,2002,3000-4000
ports, errRet := util.ParseRangeNumbers(allowPorts) ports, errRet := util.ParseRangeNumbers(allowPorts)
if errRet != nil { if errRet != nil {
err = fmt.Errorf("Parse conf error: allow_ports: %v", errRet) err = fmt.Errorf("parse conf error: allow_ports: %v", errRet)
return return
} }

View File

@ -18,9 +18,9 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/fatedier/frp/pkg/config"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/fatedier/frp/pkg/config"
) )
func init() { func init() {

View File

@ -1,4 +1,4 @@
FROM golang:1.18 AS building FROM golang:1.19 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

View File

@ -1,4 +1,4 @@
FROM golang:1.18 AS building FROM golang:1.19 AS building
COPY . /building COPY . /building
WORKDIR /building WORKDIR /building

43
go.mod
View File

@ -1,6 +1,6 @@
module github.com/fatedier/frp module github.com/fatedier/frp
go 1.16 go 1.18
require ( require (
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
@ -13,21 +13,54 @@ require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/yamux v0.0.0-20210707203944-259a57b3608c github.com/hashicorp/yamux v0.0.0-20210707203944-259a57b3608c
github.com/leodido/go-urn v1.2.1 // indirect
github.com/onsi/ginkgo v1.16.4 github.com/onsi/ginkgo v1.16.4
github.com/onsi/gomega v1.13.0 github.com/onsi/gomega v1.13.0
github.com/pires/go-proxyproto v0.6.2 github.com/pires/go-proxyproto v0.6.2
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v1.11.0 github.com/prometheus/client_golang v1.11.0
github.com/rodaine/table v1.0.1 github.com/rodaine/table v1.0.1
github.com/spf13/cobra v1.1.3 github.com/spf13/cobra v1.1.3
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
gopkg.in/ini.v1 v1.62.0 gopkg.in/ini.v1 v1.62.0
gopkg.in/square/go-jose.v2 v2.4.1 // indirect
k8s.io/apimachinery v0.21.2 k8s.io/apimachinery v0.21.2
k8s.io/client-go v0.21.2 k8s.io/client-go v0.21.2
) )
require (
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
github.com/klauspost/reedsolomon v1.9.15 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect
golang.org/x/text v0.3.6 // indirect
google.golang.org/appengine v1.6.5 // indirect
google.golang.org/protobuf v1.26.0 // indirect
gopkg.in/square/go-jose.v2 v2.4.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

2
go.sum
View File

@ -55,7 +55,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -383,7 +382,6 @@ github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVc
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E=
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=

View File

@ -5,7 +5,7 @@ ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd)
which ginkgo &> /dev/null which ginkgo &> /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "ginkgo not found, try to install..." echo "ginkgo not found, try to install..."
go install github.com/onsi/ginkgo/ginkgo@latest go install github.com/onsi/ginkgo/ginkgo@v1.16.5
fi fi
debug=false debug=false

View File

@ -18,10 +18,10 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/fatedier/frp/pkg/msg"
"github.com/coreos/go-oidc" "github.com/coreos/go-oidc"
"golang.org/x/oauth2/clientcredentials" "golang.org/x/oauth2/clientcredentials"
"github.com/fatedier/frp/pkg/msg"
) )
type OidcClientConfig struct { type OidcClientConfig struct {

View File

@ -20,10 +20,10 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"gopkg.in/ini.v1"
) )
// ClientCommonConf contains information for a client service. It is // ClientCommonConf contains information for a client service. It is
@ -214,7 +214,7 @@ func (cfg *ClientCommonConf) Validate() error {
} }
} }
if cfg.TLSEnable == false { if !cfg.TLSEnable {
if cfg.TLSCertFile != "" { if cfg.TLSCertFile != "" {
fmt.Println("WARNING! tls_cert_file is invalid when tls_enable is false") fmt.Println("WARNING! tls_cert_file is invalid when tls_enable is false")
} }
@ -281,7 +281,6 @@ func LoadAllProxyConfsFromIni(
source interface{}, source interface{},
start []string, start []string,
) (map[string]ProxyConf, map[string]VisitorConf, error) { ) (map[string]ProxyConf, map[string]VisitorConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,
@ -366,7 +365,6 @@ func LoadAllProxyConfsFromIni(
} }
func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error { func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
// Validation // Validation
localPortStr := section.Key("local_port").String() localPortStr := section.Key("local_port").String()
remotePortStr := section.Key("remote_port").String() remotePortStr := section.Key("remote_port").String()
@ -404,8 +402,12 @@ func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
} }
copySection(section, tmpsection) copySection(section, tmpsection)
tmpsection.NewKey("local_port", fmt.Sprintf("%d", localPorts[i])) if _, err := tmpsection.NewKey("local_port", fmt.Sprintf("%d", localPorts[i])); err != nil {
tmpsection.NewKey("remote_port", fmt.Sprintf("%d", remotePorts[i])) return fmt.Errorf("local_port new key in section error: %v", err)
}
if _, err := tmpsection.NewKey("remote_port", fmt.Sprintf("%d", remotePorts[i])); err != nil {
return fmt.Errorf("remote_port new key in section error: %v", err)
}
} }
return nil return nil
@ -413,6 +415,6 @@ func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
func copySection(source, target *ini.Section) { func copySection(source, target *ini.Section) {
for key, value := range source.KeysHash() { for key, value := range source.KeysHash() {
target.NewKey(key, value) _, _ = target.NewKey(key, value)
} }
} }

View File

@ -17,18 +17,17 @@ package config
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/stretchr/testify/assert"
) )
const ( const (
testUser = "test" testUser = "test"
) )
var ( var testClientBytesWithFull = []byte(`
testClientBytesWithFull = []byte(`
# [common] is integral section # [common] is integral section
[common] [common]
server_addr = 0.0.0.9 server_addr = 0.0.0.9
@ -237,7 +236,6 @@ var (
use_encryption = false use_encryption = false
use_compression = false use_compression = false
`) `)
)
func Test_LoadClientCommonConf(t *testing.T) { func Test_LoadClientCommonConf(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)

View File

@ -42,7 +42,7 @@ func ParseClientConfig(filePath string) (
} }
cfg.Complete() cfg.Complete()
if err = cfg.Validate(); err != nil { if err = cfg.Validate(); err != nil {
err = fmt.Errorf("Parse config error: %v", err) err = fmt.Errorf("parse config error: %v", err)
return return
} }

View File

@ -21,10 +21,10 @@ import (
"strconv" "strconv"
"strings" "strings"
"gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"gopkg.in/ini.v1"
) )
// Proxy // Proxy
@ -420,10 +420,6 @@ func (cfg *BaseProxyConf) checkForCli() (err error) {
return nil return nil
} }
func (cfg *BaseProxyConf) checkForSvr(conf ServerCommonConf) error {
return nil
}
// DomainConf // DomainConf
func (cfg *DomainConf) check() (err error) { func (cfg *DomainConf) check() (err error) {
if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" { if len(cfg.CustomDomains) == 0 && cfg.SubDomain == "" {

View File

@ -17,10 +17,10 @@ package config
import ( import (
"testing" "testing"
"github.com/fatedier/frp/pkg/consts"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/consts"
) )
var ( var (
@ -49,7 +49,6 @@ func Test_Proxy_UnmarshalFromIni(t *testing.T) {
source []byte source []byte
expected ProxyConf expected ProxyConf
}{ }{
{ {
sname: "ssh", sname: "ssh",
source: []byte(` source: []byte(`
@ -457,5 +456,4 @@ func Test_RangeProxy_UnmarshalFromIni(t *testing.T) {
assert.Equal(c.expected, actual) assert.Equal(c.expected, actual)
} }
} }

View File

@ -18,12 +18,12 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/go-playground/validator/v10"
"gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
plugin "github.com/fatedier/frp/pkg/plugin/server" plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/go-playground/validator/v10"
"gopkg.in/ini.v1"
) )
// ServerCommonConf contains information for a server service. It is // ServerCommonConf contains information for a server service. It is
@ -236,7 +236,6 @@ func GetDefaultServerConf() ServerCommonConf {
} }
func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) { func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
f, err := ini.LoadSources(ini.LoadOptions{ f, err := ini.LoadSources(ini.LoadOptions{
Insensitive: false, Insensitive: false,
InsensitiveSections: false, InsensitiveSections: false,
@ -308,7 +307,7 @@ func (cfg *ServerCommonConf) Complete() {
} }
func (cfg *ServerCommonConf) Validate() error { func (cfg *ServerCommonConf) Validate() error {
if cfg.DashboardTLSMode == false { if !cfg.DashboardTLSMode {
if cfg.DashboardTLSCertFile != "" { if cfg.DashboardTLSCertFile != "" {
fmt.Println("WARNING! dashboard_tls_cert_file is invalid when dashboard_tls_mode is false") fmt.Println("WARNING! dashboard_tls_cert_file is invalid when dashboard_tls_mode is false")
} }

View File

@ -17,10 +17,10 @@ package config
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
plugin "github.com/fatedier/frp/pkg/plugin/server" plugin "github.com/fatedier/frp/pkg/plugin/server"
"github.com/stretchr/testify/assert"
) )
func Test_LoadServerCommonConf(t *testing.T) { func Test_LoadServerCommonConf(t *testing.T) {
@ -126,10 +126,10 @@ func Test_LoadServerCommonConf(t *testing.T) {
HeartbeatTimeout: 99, HeartbeatTimeout: 99,
UserConnTimeout: 9, UserConnTimeout: 9,
AllowPorts: map[int]struct{}{ AllowPorts: map[int]struct{}{
10: struct{}{}, 10: {},
11: struct{}{}, 11: {},
12: struct{}{}, 12: {},
99: struct{}{}, 99: {},
}, },
MaxPoolCount: 59, MaxPoolCount: 59,
MaxPortsPerClient: 9, MaxPortsPerClient: 9,

View File

@ -75,21 +75,22 @@ func (q *BandwidthQuantity) UnmarshalString(s string) error {
f float64 f float64
err error err error
) )
if strings.HasSuffix(s, "MB") { switch {
case strings.HasSuffix(s, "MB"):
base = MB base = MB
fstr := strings.TrimSuffix(s, "MB") fstr := strings.TrimSuffix(s, "MB")
f, err = strconv.ParseFloat(fstr, 64) f, err = strconv.ParseFloat(fstr, 64)
if err != nil { if err != nil {
return err return err
} }
} else if strings.HasSuffix(s, "KB") { case strings.HasSuffix(s, "KB"):
base = KB base = KB
fstr := strings.TrimSuffix(s, "KB") fstr := strings.TrimSuffix(s, "KB")
f, err = strconv.ParseFloat(fstr, 64) f, err = strconv.ParseFloat(fstr, 64)
if err != nil { if err != nil {
return err return err
} }
} else { default:
return errors.New("unit not support") return errors.New("unit not support")
} }

View File

@ -21,9 +21,7 @@ import (
"text/template" "text/template"
) )
var ( var glbEnvs map[string]string
glbEnvs map[string]string
)
func init() { func init() {
glbEnvs = make(map[string]string) glbEnvs = make(map[string]string)

View File

@ -18,9 +18,9 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/fatedier/frp/pkg/consts"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/consts"
) )
// Visitor // Visitor
@ -136,6 +136,7 @@ func (cfg *BaseVisitorConf) check() (err error) {
} }
func (cfg *BaseVisitorConf) unmarshalFromIni(prefix string, name string, section *ini.Section) error { func (cfg *BaseVisitorConf) unmarshalFromIni(prefix string, name string, section *ini.Section) error {
_ = section
// Custom decoration after basic unmarshal: // Custom decoration after basic unmarshal:
// proxy name // proxy name

View File

@ -17,10 +17,10 @@ package config
import ( import (
"testing" "testing"
"github.com/fatedier/frp/pkg/consts"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"github.com/fatedier/frp/pkg/consts"
) )
const testVisitorPrefix = "test." const testVisitorPrefix = "test."

View File

@ -16,26 +16,26 @@ package consts
var ( var (
// proxy status // proxy status
Idle string = "idle" Idle = "idle"
Working string = "working" Working = "working"
Closed string = "closed" Closed = "closed"
Online string = "online" Online = "online"
Offline string = "offline" Offline = "offline"
// proxy type // proxy type
TCPProxy string = "tcp" TCPProxy = "tcp"
UDPProxy string = "udp" UDPProxy = "udp"
TCPMuxProxy string = "tcpmux" TCPMuxProxy = "tcpmux"
HTTPProxy string = "http" HTTPProxy = "http"
HTTPSProxy string = "https" HTTPSProxy = "https"
STCPProxy string = "stcp" STCPProxy = "stcp"
XTCPProxy string = "xtcp" XTCPProxy = "xtcp"
SUDPProxy string = "sudp" SUDPProxy = "sudp"
// authentication method // authentication method
TokenAuthMethod string = "token" TokenAuthMethod = "token"
OidcAuthMethod string = "oidc" OidcAuthMethod = "oidc"
// TCP multiplexer // TCP multiplexer
HTTPConnectTCPMultiplexer string = "httpconnect" HTTPConnectTCPMultiplexer = "httpconnect"
) )

View File

@ -30,7 +30,7 @@ func EnablePrometheus() {
sm.Add(prometheus.ServerMetrics) sm.Add(prometheus.ServerMetrics)
} }
var sm *serverMetrics = &serverMetrics{} var sm = &serverMetrics{}
func init() { func init() {
metrics.Register(sm) metrics.Register(sm)

View File

@ -23,9 +23,12 @@ import (
server "github.com/fatedier/frp/server/metrics" server "github.com/fatedier/frp/server/metrics"
) )
var sm *serverMetrics = newServerMetrics() var (
var ServerMetrics server.ServerMetrics sm = newServerMetrics()
var StatsCollector Collector
ServerMetrics server.ServerMetrics
StatsCollector Collector
)
func init() { func init() {
ServerMetrics = sm ServerMetrics = sm

View File

@ -4,5 +4,7 @@ import (
"github.com/fatedier/frp/pkg/metrics/aggregate" "github.com/fatedier/frp/pkg/metrics/aggregate"
) )
var EnableMem = aggregate.EnableMem var (
var EnablePrometheus = aggregate.EnablePrometheus EnableMem = aggregate.EnableMem
EnablePrometheus = aggregate.EnablePrometheus
)

View File

@ -1,9 +1,9 @@
package prometheus package prometheus
import ( import (
"github.com/fatedier/frp/server/metrics"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/fatedier/frp/server/metrics"
) )
const ( const (

View File

@ -22,9 +22,7 @@ import (
type Message = jsonMsg.Message type Message = jsonMsg.Message
var ( var msgCtl *jsonMsg.MsgCtl
msgCtl *jsonMsg.MsgCtl
)
func init() { func init() {
msgCtl = jsonMsg.NewMsgCtl() msgCtl = jsonMsg.NewMsgCtl()

View File

@ -37,8 +37,7 @@ const (
TypeNatHoleSid = '5' TypeNatHoleSid = '5'
) )
var ( var msgTypeMap = map[byte]interface{}{
msgTypeMap = map[byte]interface{}{
TypeLogin: Login{}, TypeLogin: Login{},
TypeLoginResp: LoginResp{}, TypeLoginResp: LoginResp{},
TypeNewProxy: NewProxy{}, TypeNewProxy: NewProxy{},
@ -58,7 +57,6 @@ var (
TypeNatHoleClientDetectOK: NatHoleClientDetectOK{}, TypeNatHoleClientDetectOK: NatHoleClientDetectOK{},
TypeNatHoleSid: NatHoleSid{}, TypeNatHoleSid: NatHoleSid{},
} }
)
// When frpc start, client send this message to login to server. // When frpc start, client send this message to login to server.
type Login struct { type Login struct {
@ -129,8 +127,7 @@ type NewWorkConn struct {
Timestamp int64 `json:"timestamp,omitempty"` Timestamp int64 `json:"timestamp,omitempty"`
} }
type ReqWorkConn struct { type ReqWorkConn struct{}
}
type StartWorkConn struct { type StartWorkConn struct {
ProxyName string `json:"proxy_name,omitempty"` ProxyName string `json:"proxy_name,omitempty"`
@ -187,8 +184,7 @@ type NatHoleResp struct {
Error string `json:"error,omitempty"` Error string `json:"error,omitempty"`
} }
type NatHoleClientDetectOK struct { type NatHoleClientDetectOK struct{}
}
type NatHoleSid struct { type NatHoleSid struct {
Sid string `json:"sid,omitempty"` Sid string `json:"sid,omitempty"`

View File

@ -7,15 +7,15 @@ import (
"sync" "sync"
"time" "time"
"github.com/fatedier/golib/errors"
"github.com/fatedier/golib/pool"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/golib/errors"
"github.com/fatedier/golib/pool"
) )
// Timeout seconds. // NatHoleTimeout seconds.
var NatHoleTimeout int64 = 10 var NatHoleTimeout int64 = 10
type SidRequest struct { type SidRequest struct {
@ -107,7 +107,7 @@ func (nc *Controller) HandleVisitor(m *msg.NatHoleVisitor, raddr *net.UDPAddr) {
session := &Session{ session := &Session{
Sid: sid, Sid: sid,
VisitorAddr: raddr, VisitorAddr: raddr,
NotifyCh: make(chan struct{}, 0), NotifyCh: make(chan struct{}),
} }
nc.mu.Lock() nc.mu.Lock()
clientCfg, ok := nc.clientCfgs[m.ProxyName] clientCfg, ok := nc.clientCfgs[m.ProxyName]
@ -115,14 +115,14 @@ func (nc *Controller) HandleVisitor(m *msg.NatHoleVisitor, raddr *net.UDPAddr) {
nc.mu.Unlock() nc.mu.Unlock()
errInfo := fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName) errInfo := fmt.Sprintf("xtcp server for [%s] doesn't exist", m.ProxyName)
log.Debug(errInfo) log.Debug(errInfo)
nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr) _, _ = nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr)
return return
} }
if m.SignKey != util.GetAuthKey(clientCfg.Sk, m.Timestamp) { if m.SignKey != util.GetAuthKey(clientCfg.Sk, m.Timestamp) {
nc.mu.Unlock() nc.mu.Unlock()
errInfo := fmt.Sprintf("xtcp connection of [%s] auth failed", m.ProxyName) errInfo := fmt.Sprintf("xtcp connection of [%s] auth failed", m.ProxyName)
log.Debug(errInfo) log.Debug(errInfo)
nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr) _, _ = nc.listener.WriteToUDP(nc.GenNatHoleResponse(nil, errInfo), raddr)
return return
} }
@ -151,7 +151,7 @@ func (nc *Controller) HandleVisitor(m *msg.NatHoleVisitor, raddr *net.UDPAddr) {
case <-session.NotifyCh: case <-session.NotifyCh:
resp := nc.GenNatHoleResponse(session, "") resp := nc.GenNatHoleResponse(session, "")
log.Trace("send nat hole response to visitor") log.Trace("send nat hole response to visitor")
nc.listener.WriteToUDP(resp, raddr) _, _ = nc.listener.WriteToUDP(resp, raddr)
case <-time.After(time.Duration(NatHoleTimeout) * time.Second): case <-time.After(time.Duration(NatHoleTimeout) * time.Second):
return return
} }
@ -169,7 +169,7 @@ func (nc *Controller) HandleClient(m *msg.NatHoleClient, raddr *net.UDPAddr) {
resp := nc.GenNatHoleResponse(session, "") resp := nc.GenNatHoleResponse(session, "")
log.Trace("send nat hole response to client") log.Trace("send nat hole response to client")
nc.listener.WriteToUDP(resp, raddr) _, _ = nc.listener.WriteToUDP(resp, raddr)
} }
func (nc *Controller) GenNatHoleResponse(session *Session, errInfo string) []byte { func (nc *Controller) GenNatHoleResponse(session *Session, errInfo string) []byte {

View File

@ -87,16 +87,19 @@ func NewHTTP2HTTPSPlugin(params map[string]string) (Plugin, error) {
p.s = &http.Server{ p.s = &http.Server{
Handler: rp, Handler: rp,
ReadHeaderTimeout: 0,
} }
go p.s.Serve(listener) go func() {
_ = p.s.Serve(listener)
}()
return p, nil return p, nil
} }
func (p *HTTP2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) { func (p *HTTP2HTTPSPlugin) 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)
} }
func (p *HTTP2HTTPSPlugin) Name() string { func (p *HTTP2HTTPSPlugin) Name() string {

View File

@ -22,10 +22,10 @@ import (
"net/http" "net/http"
"strings" "strings"
frpNet "github.com/fatedier/frp/pkg/util/net"
frpIo "github.com/fatedier/golib/io" frpIo "github.com/fatedier/golib/io"
gnet "github.com/fatedier/golib/net" gnet "github.com/fatedier/golib/net"
frpNet "github.com/fatedier/frp/pkg/util/net"
) )
const PluginHTTPProxy = "http_proxy" const PluginHTTPProxy = "http_proxy"
@ -56,7 +56,9 @@ func NewHTTPProxyPlugin(params map[string]string) (Plugin, error) {
Handler: hp, Handler: hp,
} }
go hp.s.Serve(listener) go func() {
_ = hp.s.Serve(listener)
}()
return hp, nil return hp, nil
} }
@ -86,8 +88,7 @@ func (hp *HTTPProxy) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBuf
return return
} }
hp.l.PutConn(sc) _ = hp.l.PutConn(sc)
return
} }
func (hp *HTTPProxy) Close() error { func (hp *HTTPProxy) Close() error {
@ -153,7 +154,7 @@ func (hp *HTTPProxy) ConnectHandler(rw http.ResponseWriter, req *http.Request) {
client.Close() client.Close()
return return
} }
client.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) _, _ = client.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
go frpIo.Join(remote, client) go frpIo.Join(remote, client)
} }
@ -188,7 +189,10 @@ func (hp *HTTPProxy) handleConnectReq(req *http.Request, rwc io.ReadWriteCloser)
defer rwc.Close() defer rwc.Close()
if ok := hp.Auth(req); !ok { if ok := hp.Auth(req); !ok {
res := getBadResponse() res := getBadResponse()
res.Write(rwc) _ = res.Write(rwc)
if res.Body != nil {
res.Body.Close()
}
return return
} }
@ -200,10 +204,10 @@ func (hp *HTTPProxy) handleConnectReq(req *http.Request, rwc io.ReadWriteCloser)
ProtoMajor: 1, ProtoMajor: 1,
ProtoMinor: 1, ProtoMinor: 1,
} }
res.Write(rwc) _ = res.Write(rwc)
return return
} }
rwc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) _, _ = rwc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
frpIo.Join(remote, rwc) frpIo.Join(remote, rwc)
} }

View File

@ -106,7 +106,9 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
} }
ln := tls.NewListener(listener, tlsConfig) ln := tls.NewListener(listener, tlsConfig)
go p.s.Serve(ln) go func() {
_ = p.s.Serve(ln)
}()
return p, nil return p, nil
} }
@ -122,7 +124,7 @@ func (p *HTTPS2HTTPPlugin) genTLSConfig() (*tls.Config, error) {
func (p *HTTPS2HTTPPlugin) Handle(conn io.ReadWriteCloser, realConn net.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)
} }
func (p *HTTPS2HTTPPlugin) Name() string { func (p *HTTPS2HTTPPlugin) Name() string {

View File

@ -111,7 +111,9 @@ func NewHTTPS2HTTPSPlugin(params map[string]string) (Plugin, error) {
} }
ln := tls.NewListener(listener, tlsConfig) ln := tls.NewListener(listener, tlsConfig)
go p.s.Serve(ln) go func() {
_ = p.s.Serve(ln)
}()
return p, nil return p, nil
} }
@ -127,7 +129,7 @@ func (p *HTTPS2HTTPSPlugin) genTLSConfig() (*tls.Config, error) {
func (p *HTTPS2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) { func (p *HTTPS2HTTPSPlugin) 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)
} }
func (p *HTTPS2HTTPSPlugin) Name() string { func (p *HTTPS2HTTPSPlugin) Name() string {

View File

@ -19,9 +19,9 @@ import (
"log" "log"
"net" "net"
frpNet "github.com/fatedier/frp/pkg/util/net"
gosocks5 "github.com/armon/go-socks5" gosocks5 "github.com/armon/go-socks5"
frpNet "github.com/fatedier/frp/pkg/util/net"
) )
const PluginSocks5 = "socks5" const PluginSocks5 = "socks5"
@ -32,9 +32,6 @@ func init() {
type Socks5Plugin struct { type Socks5Plugin struct {
Server *gosocks5.Server Server *gosocks5.Server
user string
passwd string
} }
func NewSocks5Plugin(params map[string]string) (p Plugin, err error) { func NewSocks5Plugin(params map[string]string) (p Plugin, err error) {
@ -56,7 +53,7 @@ func NewSocks5Plugin(params map[string]string) (p Plugin, err error) {
func (sp *Socks5Plugin) Handle(conn io.ReadWriteCloser, realConn net.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)
} }
func (sp *Socks5Plugin) Name() string { func (sp *Socks5Plugin) Name() string {

View File

@ -19,9 +19,9 @@ import (
"net" "net"
"net/http" "net/http"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/gorilla/mux" "github.com/gorilla/mux"
frpNet "github.com/fatedier/frp/pkg/util/net"
) )
const PluginStaticFile = "static_file" const PluginStaticFile = "static_file"
@ -69,13 +69,15 @@ func NewStaticFilePlugin(params map[string]string) (Plugin, error) {
sp.s = &http.Server{ sp.s = &http.Server{
Handler: router, Handler: router,
} }
go sp.s.Serve(listener) go func() {
_ = sp.s.Serve(listener)
}()
return sp, nil return sp, nil
} }
func (sp *StaticFilePlugin) Handle(conn io.ReadWriteCloser, realConn net.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)
} }
func (sp *StaticFilePlugin) Name() string { func (sp *StaticFilePlugin) Name() string {

View File

@ -57,7 +57,9 @@ func (uds *UnixDomainSocketPlugin) Handle(conn io.ReadWriteCloser, realConn net.
return return
} }
if len(extraBufToLocal) > 0 { if len(extraBufToLocal) > 0 {
localConn.Write(extraBufToLocal) if _, err := localConn.Write(extraBufToLocal); err != nil {
return
}
} }
frpIo.Join(localConn, conn) frpIo.Join(localConn, conn)

View File

@ -43,12 +43,12 @@ type httpPlugin struct {
} }
func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin { func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
var url = fmt.Sprintf("%s%s", options.Addr, options.Path) url := fmt.Sprintf("%s%s", options.Addr, options.Path)
var client *http.Client var client *http.Client
if strings.HasPrefix(url, "https://") { if strings.HasPrefix(url, "https://") {
tr := &http.Transport{ tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: options.TLSVerify == false}, TLSClientConfig: &tls.Config{InsecureSkipVerify: !options.TLSVerify},
} }
client = &http.Client{Transport: tr} client = &http.Client{Transport: tr}
} else { } else {

View File

@ -154,9 +154,8 @@ func (m *Manager) CloseProxy(content *CloseProxyContent) error {
if len(errs) > 0 { if len(errs) > 0 {
return fmt.Errorf("send CloseProxy request to plugin errors: %s", strings.Join(errs, "; ")) return fmt.Errorf("send CloseProxy request to plugin errors: %s", strings.Join(errs, "; "))
} else {
return nil
} }
return nil
} }
func (m *Manager) Ping(content *PingContent) (*PingContent, error) { func (m *Manager) Ping(content *PingContent) (*PingContent, error) {

View File

@ -20,10 +20,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/golib/errors" "github.com/fatedier/golib/errors"
"github.com/fatedier/golib/pool" "github.com/fatedier/golib/pool"
"github.com/fatedier/frp/pkg/msg"
) )
func NewUDPPacket(buf []byte, laddr, raddr *net.UDPAddr) *msg.UDPPacket { func NewUDPPacket(buf []byte, laddr, raddr *net.UDPAddr) *msg.UDPPacket {
@ -47,7 +47,7 @@ func ForwardUserConn(udpConn *net.UDPConn, readCh <-chan *msg.UDPPacket, sendCh
if err != nil { if err != nil {
continue continue
} }
udpConn.WriteToUDP(buf, udpMsg.RemoteAddr) _, _ = udpConn.WriteToUDP(buf, udpMsg.RemoteAddr)
} }
}() }()
@ -70,9 +70,7 @@ func ForwardUserConn(udpConn *net.UDPConn, readCh <-chan *msg.UDPPacket, sendCh
} }
func Forwarder(dstAddr *net.UDPAddr, readCh <-chan *msg.UDPPacket, sendCh chan<- msg.Message, bufSize int) { func Forwarder(dstAddr *net.UDPAddr, readCh <-chan *msg.UDPPacket, sendCh chan<- msg.Message, bufSize int) {
var ( var mu sync.RWMutex
mu sync.RWMutex
)
udpConnMap := make(map[string]*net.UDPConn) udpConnMap := make(map[string]*net.UDPConn)
// read from dstAddr and write to sendCh // read from dstAddr and write to sendCh
@ -87,7 +85,7 @@ func Forwarder(dstAddr *net.UDPAddr, readCh <-chan *msg.UDPPacket, sendCh chan<-
buf := pool.GetBuf(bufSize) buf := pool.GetBuf(bufSize)
for { for {
udpConn.SetReadDeadline(time.Now().Add(30 * time.Second)) _ = udpConn.SetReadDeadline(time.Now().Add(30 * time.Second))
n, _, err := udpConn.ReadFromUDP(buf) n, _, err := udpConn.ReadFromUDP(buf)
if err != nil { if err != nil {
return return

View File

@ -19,7 +19,7 @@ func newCustomTLSKeyPair(certfile, keyfile string) (*tls.Certificate, error) {
} }
func newRandomTLSKeyPair() *tls.Certificate { func newRandomTLSKeyPair() *tls.Certificate {
key, err := rsa.GenerateKey(rand.Reader, 1024) key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -58,7 +58,7 @@ func newCertPool(caPath string) (*x509.CertPool, error) {
} }
func NewServerTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) { func NewServerTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) {
var base = &tls.Config{} base := &tls.Config{}
if certPath == "" || keyPath == "" { if certPath == "" || keyPath == "" {
// server will generate tls conf by itself // server will generate tls conf by itself
@ -87,7 +87,7 @@ func NewServerTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) {
} }
func NewClientTLSConfig(certPath, keyPath, caPath, serverName string) (*tls.Config, error) { func NewClientTLSConfig(certPath, keyPath, caPath, serverName string) (*tls.Config, error) {
var base = &tls.Config{} base := &tls.Config{}
if certPath == "" || keyPath == "" { if certPath == "" || keyPath == "" {
// client will not generate tls conf by itself // client will not generate tls conf by itself

View File

@ -40,19 +40,19 @@ func SetLogFile(logWay string, logFile string, maxdays int64, disableLogColor bo
if logWay == "console" { if logWay == "console" {
params := "" params := ""
if disableLogColor { if disableLogColor {
params = fmt.Sprintf(`{"color": false}`) params = `{"color": false}`
} }
Log.SetLogger("console", params) _ = Log.SetLogger("console", params)
} else { } else {
params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays) params := fmt.Sprintf(`{"filename": "%s", "maxdays": %d}`, logFile, maxdays)
Log.SetLogger("file", params) _ = Log.SetLogger("file", params)
} }
} }
// SetLogLevel set log level, default is warning // SetLogLevel set log level, default is warning
// value: error, warning, info, debug, trace // value: error, warning, info, debug, trace
func SetLogLevel(logLevel string) { func SetLogLevel(logLevel string) {
level := 4 // warning var level int
switch logLevel { switch logLevel {
case "error": case "error":
level = 3 level = 3
@ -65,7 +65,7 @@ func SetLogLevel(logLevel string) {
case "trace": case "trace":
level = 8 level = 8
default: default:
level = 4 level = 4 // warning
} }
Log.SetLevel(level) Log.SetLevel(level)
} }

View File

@ -32,8 +32,8 @@ func ListenKcp(address string) (l *KCPListener, err error) {
if err != nil { if err != nil {
return l, err return l, err
} }
listener.SetReadBuffer(4194304) _ = listener.SetReadBuffer(4194304)
listener.SetWriteBuffer(4194304) _ = listener.SetWriteBuffer(4194304)
l = &KCPListener{ l = &KCPListener{
listener: listener, listener: listener,

View File

@ -23,32 +23,30 @@ import (
gnet "github.com/fatedier/golib/net" gnet "github.com/fatedier/golib/net"
) )
var ( var FRPTLSHeadByte = 0x17
FRPTLSHeadByte = 0x17
)
func CheckAndEnableTLSServerConnWithTimeout( func CheckAndEnableTLSServerConnWithTimeout(
c net.Conn, tlsConfig *tls.Config, tlsOnly bool, timeout time.Duration, c net.Conn, tlsConfig *tls.Config, tlsOnly bool, timeout time.Duration,
) (out net.Conn, isTLS bool, custom bool, err error) { ) (out net.Conn, isTLS bool, custom bool, 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
c.SetReadDeadline(time.Now().Add(timeout)) _ = c.SetReadDeadline(time.Now().Add(timeout))
n, err = r.Read(buf) n, err = r.Read(buf)
c.SetReadDeadline(time.Time{}) _ = c.SetReadDeadline(time.Time{})
if err != nil { if err != nil {
return return
} }
if n == 1 && int(buf[0]) == FRPTLSHeadByte { switch {
case n == 1 && int(buf[0]) == FRPTLSHeadByte:
out = tls.Server(c, tlsConfig) out = tls.Server(c, tlsConfig)
isTLS = true isTLS = true
custom = true custom = true
} else if n == 1 && int(buf[0]) == 0x16 { case n == 1 && int(buf[0]) == 0x16:
out = tls.Server(sc, tlsConfig) out = tls.Server(sc, tlsConfig)
isTLS = true isTLS = true
} else { default:
if tlsOnly { if tlsOnly {
err = fmt.Errorf("non-TLS connection received on a TlsOnly server") err = fmt.Errorf("non-TLS connection received on a TlsOnly server")
return return

View File

@ -55,7 +55,7 @@ func NewFakeUDPConn(l *UDPListener, laddr, raddr net.Addr) *FakeUDPConn {
for { for {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
fc.mu.RLock() fc.mu.RLock()
if time.Now().Sub(fc.lastActive) > 10*time.Second { if time.Since(fc.lastActive) > 10*time.Second {
fc.mu.RUnlock() fc.mu.RUnlock()
fc.Close() fc.Close()
break break
@ -68,8 +68,7 @@ func NewFakeUDPConn(l *UDPListener, laddr, raddr net.Addr) *FakeUDPConn {
func (c *FakeUDPConn) putPacket(content []byte) { func (c *FakeUDPConn) putPacket(content []byte) {
defer func() { defer func() {
if err := recover(); err != nil { _ = recover()
}
}() }()
select { select {
@ -109,7 +108,7 @@ func (c *FakeUDPConn) Write(b []byte) (n int, err error) {
LocalAddr: c.localAddr, LocalAddr: c.localAddr,
RemoteAddr: c.remoteAddr, RemoteAddr: c.remoteAddr,
} }
c.l.writeUDPPacket(packet) _ = c.l.writeUDPPacket(packet)
c.mu.Lock() c.mu.Lock()
c.lastActive = time.Now() c.lastActive = time.Now()
@ -208,7 +207,7 @@ func ListenUDP(bindAddr string, bindPort int) (l *UDPListener, err error) {
} }
if addr, ok := packet.RemoteAddr.(*net.UDPAddr); ok { if addr, ok := packet.RemoteAddr.(*net.UDPAddr); ok {
readConn.WriteToUDP(packet.Buf, addr) _, _ = readConn.WriteToUDP(packet.Buf, addr)
} }
} }
}() }()

View File

@ -9,9 +9,7 @@ import (
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
) )
var ( var ErrWebsocketListenerClosed = errors.New("websocket listener closed")
ErrWebsocketListenerClosed = errors.New("websocket listener closed")
)
const ( const (
FrpWebsocketPath = "/~!frp" FrpWebsocketPath = "/~!frp"
@ -22,7 +20,6 @@ type WebsocketListener struct {
acceptCh chan net.Conn acceptCh chan net.Conn
server *http.Server server *http.Server
httpMutex *http.ServeMux
} }
// NewWebsocketListener to handle websocket connections // NewWebsocketListener to handle websocket connections
@ -47,7 +44,9 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
Handler: muxer, Handler: muxer,
} }
go wl.server.Serve(ln) go func() {
_ = wl.server.Serve(ln)
}()
return return
} }

View File

@ -22,9 +22,10 @@ import (
"net/http" "net/http"
"time" "time"
gnet "github.com/fatedier/golib/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
gnet "github.com/fatedier/golib/net"
) )
type HTTPConnectTCPMuxer struct { type HTTPConnectTCPMuxer struct {
@ -66,7 +67,11 @@ func (muxer *HTTPConnectTCPMuxer) sendConnectResponse(c net.Conn, reqInfo map[st
if muxer.passthrough { if muxer.passthrough {
return nil return nil
} }
return util.OkResponse().Write(c) res := util.OkResponse()
if res.Body != nil {
defer res.Body.Close()
}
return res.Write(c)
} }
func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn, map[string]string, error) { func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn, map[string]string, error) {
@ -82,11 +87,15 @@ func (muxer *HTTPConnectTCPMuxer) getHostFromHTTPConnect(c net.Conn) (net.Conn,
reqInfoMap["Scheme"] = "tcp" reqInfoMap["Scheme"] = "tcp"
reqInfoMap["HTTPUser"] = httpUser reqInfoMap["HTTPUser"] = httpUser
var outConn net.Conn = c outConn := c
if muxer.passthrough { if muxer.passthrough {
outConn = sc outConn = sc
if muxer.authRequired && httpUser == "" { if muxer.authRequired && httpUser == "" {
util.ProxyUnauthorizedResponse().Write(c) resp := util.ProxyUnauthorizedResponse()
if resp.Body != nil {
defer resp.Body.Close()
}
_ = resp.Write(c)
outConn = c outConn = c
} }
} }

View File

@ -60,10 +60,8 @@ func CanonicalHost(host string) (string, error) {
return "", err return "", err
} }
} }
if strings.HasSuffix(host, ".") {
// Strip trailing dot from fully qualified domain names. // Strip trailing dot from fully qualified domain names.
host = host[:len(host)-1] host = strings.TrimSuffix(host, ".")
}
return host, nil return host, nil
} }

View File

@ -44,7 +44,7 @@ func RandIDWithLen(idLen int) (id string, err error) {
} }
func GetAuthKey(token string, timestamp int64) (key string) { func GetAuthKey(token string, timestamp int64) (key string) {
token = token + fmt.Sprintf("%d", timestamp) token += fmt.Sprintf("%d", timestamp)
md5Ctx := md5.New() md5Ctx := md5.New()
md5Ctx.Write([]byte(token)) md5Ctx.Write([]byte(token))
data := md5Ctx.Sum(nil) data := md5Ctx.Sum(nil)
@ -70,7 +70,8 @@ func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
numArray := strings.Split(numRangeStr, "-") numArray := strings.Split(numRangeStr, "-")
// length: only 1 or 2 is correct // length: only 1 or 2 is correct
rangeType := len(numArray) rangeType := len(numArray)
if rangeType == 1 { switch rangeType {
case 1:
// single number // single number
singleNum, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64) singleNum, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
if errRet != nil { if errRet != nil {
@ -78,7 +79,7 @@ func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
return return
} }
numbers = append(numbers, singleNum) numbers = append(numbers, singleNum)
} else if rangeType == 2 { case 2:
// range numbers // range numbers
min, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64) min, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
if errRet != nil { if errRet != nil {
@ -97,7 +98,7 @@ func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
for i := min; i <= max; i++ { for i := min; i <= max; i++ {
numbers = append(numbers, i) numbers = append(numbers, i)
} }
} else { default:
err = fmt.Errorf("range number is invalid") err = fmt.Errorf("range number is invalid")
return return
} }

View File

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

View File

@ -23,27 +23,26 @@ import (
"log" "log"
"net" "net"
"net/http" "net/http"
"net/http/httputil"
"net/url" "net/url"
"strings" "strings"
"time" "time"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
frpLog "github.com/fatedier/frp/pkg/util/log" frpLog "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/golib/pool"
) )
var ( var ErrNoRouteFound = errors.New("no route found")
ErrNoRouteFound = errors.New("no route found")
)
type HTTPReverseProxyOptions struct { type HTTPReverseProxyOptions struct {
ResponseHeaderTimeoutS int64 ResponseHeaderTimeoutS int64
} }
type HTTPReverseProxy struct { type HTTPReverseProxy struct {
proxy *ReverseProxy proxy *httputil.ReverseProxy
vhostRouter *Routers vhostRouter *Routers
responseHeaderTimeout time.Duration responseHeaderTimeout time.Duration
@ -57,7 +56,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second, responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
vhostRouter: vhostRouter, vhostRouter: vhostRouter,
} }
proxy := &ReverseProxy{ proxy := &httputil.ReverseProxy{
// Modify incoming requests by route policies. // Modify incoming requests by route policies.
Director: func(req *http.Request) { Director: func(req *http.Request) {
req.URL.Scheme = "http" req.URL.Scheme = "http"
@ -81,7 +80,6 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
} else { } else {
req.URL.Host = req.Host req.URL.Host = req.Host
} }
}, },
// Create a connection to one proxy routed by route policy. // Create a connection to one proxy routed by route policy.
Transport: &http.Transport{ Transport: &http.Transport{
@ -114,7 +112,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) { ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
frpLog.Warn("do http proxy request [host: %s] error: %v", req.Host, err) frpLog.Warn("do http proxy request [host: %s] error: %v", req.Host, err)
rw.WriteHeader(http.StatusNotFound) rw.WriteHeader(http.StatusNotFound)
rw.Write(getNotFoundPageContent()) _, _ = rw.Write(getNotFoundPageContent())
}, },
} }
rp.proxy = proxy rp.proxy = proxy
@ -257,10 +255,28 @@ func (rp *HTTPReverseProxy) connectHandler(rw http.ResponseWriter, req *http.Req
client.Close() client.Close()
return return
} }
req.Write(remote) _ = req.Write(remote)
go frpIo.Join(remote, client) go frpIo.Join(remote, client)
} }
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
// Case insensitive prefix match. See Issue 22736.
if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) {
return
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
return
}
cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
return
}
return cs[:s], cs[s+1:], true
}
func (rp *HTTPReverseProxy) injectRequestInfoToCtx(req *http.Request) *http.Request { func (rp *HTTPReverseProxy) injectRequestInfoToCtx(req *http.Request) *http.Request {
newctx := req.Context() newctx := req.Context()
newctx = context.WithValue(newctx, RouteInfoURL, req.URL.Path) newctx = context.WithValue(newctx, RouteInfoURL, req.URL.Path)

View File

@ -24,9 +24,7 @@ import (
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
) )
var ( var NotFoundPagePath = ""
NotFoundPagePath = ""
)
const ( const (
NotFound = `<!DOCTYPE html> NotFound = `<!DOCTYPE html>

View File

@ -1,636 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// HTTP reverse proxy handler
package vhost
import (
"context"
"encoding/base64"
"fmt"
"io"
"log"
"net"
"net/http"
"net/textproto"
"net/url"
"strings"
"sync"
"time"
"golang.org/x/net/http/httpguts"
)
// ReverseProxy is an HTTP Handler that takes an incoming request and
// sends it to another server, proxying the response back to the
// client.
//
// ReverseProxy by default sets the client IP as the value of the
// X-Forwarded-For header.
//
// If an X-Forwarded-For header already exists, the client IP is
// appended to the existing values. As a special case, if the header
// exists in the Request.Header map but has a nil value (such as when
// set by the Director func), the X-Forwarded-For header is
// not modified.
//
// To prevent IP spoofing, be sure to delete any pre-existing
// X-Forwarded-For header coming from the client or
// an untrusted proxy.
type ReverseProxy struct {
// Director must be a function which modifies
// the request into a new request to be sent
// using Transport. Its response is then copied
// back to the original client unmodified.
// Director must not access the provided Request
// after returning.
Director func(*http.Request)
// The transport used to perform proxy requests.
// If nil, http.DefaultTransport is used.
Transport http.RoundTripper
// FlushInterval specifies the flush interval
// to flush to the client while copying the
// response body.
// If zero, no periodic flushing is done.
// A negative value means to flush immediately
// after each write to the client.
// The FlushInterval is ignored when ReverseProxy
// recognizes a response as a streaming response, or
// if its ContentLength is -1; for such responses, writes
// are flushed to the client immediately.
FlushInterval time.Duration
// ErrorLog specifies an optional logger for errors
// that occur when attempting to proxy the request.
// If nil, logging is done via the log package's standard logger.
ErrorLog *log.Logger
// BufferPool optionally specifies a buffer pool to
// get byte slices for use by io.CopyBuffer when
// copying HTTP response bodies.
BufferPool BufferPool
// ModifyResponse is an optional function that modifies the
// Response from the backend. It is called if the backend
// returns a response at all, with any HTTP status code.
// If the backend is unreachable, the optional ErrorHandler is
// called without any call to ModifyResponse.
//
// If ModifyResponse returns an error, ErrorHandler is called
// with its error value. If ErrorHandler is nil, its default
// implementation is used.
ModifyResponse func(*http.Response) error
// ErrorHandler is an optional function that handles errors
// reaching the backend or errors from ModifyResponse.
//
// If nil, the default is to log the provided error and return
// a 502 Status Bad Gateway response.
ErrorHandler func(http.ResponseWriter, *http.Request, error)
}
// A BufferPool is an interface for getting and returning temporary
// byte slices for use by io.CopyBuffer.
type BufferPool interface {
Get() []byte
Put([]byte)
}
func singleJoiningSlash(a, b string) string {
aslash := strings.HasSuffix(a, "/")
bslash := strings.HasPrefix(b, "/")
switch {
case aslash && bslash:
return a + b[1:]
case !aslash && !bslash:
return a + "/" + b
}
return a + b
}
func joinURLPath(a, b *url.URL) (path, rawpath string) {
if a.RawPath == "" && b.RawPath == "" {
return singleJoiningSlash(a.Path, b.Path), ""
}
// Same as singleJoiningSlash, but uses EscapedPath to determine
// whether a slash should be added
apath := a.EscapedPath()
bpath := b.EscapedPath()
aslash := strings.HasSuffix(apath, "/")
bslash := strings.HasPrefix(bpath, "/")
switch {
case aslash && bslash:
return a.Path + b.Path[1:], apath + bpath[1:]
case !aslash && !bslash:
return a.Path + "/" + b.Path, apath + "/" + bpath
}
return a.Path + b.Path, apath + bpath
}
// NewSingleHostReverseProxy returns a new ReverseProxy that routes
// URLs to the scheme, host, and base path provided in target. If the
// target's path is "/base" and the incoming request was for "/dir",
// the target request will be for /base/dir.
// NewSingleHostReverseProxy does not rewrite the Host header.
// To rewrite Host headers, use ReverseProxy directly with a custom
// Director policy.
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
targetQuery := target.RawQuery
director := func(req *http.Request) {
req.URL.Scheme = target.Scheme
req.URL.Host = target.Host
req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
if _, ok := req.Header["User-Agent"]; !ok {
// explicitly disable User-Agent so it's not set to default value
req.Header.Set("User-Agent", "")
}
}
return &ReverseProxy{Director: director}
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
// Hop-by-hop headers. These are removed when sent to the backend.
// As of RFC 7230, hop-by-hop headers are required to appear in the
// Connection header field. These are the headers defined by the
// obsoleted RFC 2616 (section 13.5.1) and are used for backward
// compatibility.
var hopHeaders = []string{
"Connection",
"Proxy-Connection", // non-standard but still sent by libcurl and rejected by e.g. google
"Keep-Alive",
"Proxy-Authenticate",
"Proxy-Authorization",
"Te", // canonicalized version of "TE"
"Trailer", // not Trailers per URL above; https://www.rfc-editor.org/errata_search.php?eid=4522
"Transfer-Encoding",
"Upgrade",
}
func (p *ReverseProxy) defaultErrorHandler(rw http.ResponseWriter, req *http.Request, err error) {
p.logf("http: proxy error: %v", err)
rw.WriteHeader(http.StatusBadGateway)
}
func (p *ReverseProxy) getErrorHandler() func(http.ResponseWriter, *http.Request, error) {
if p.ErrorHandler != nil {
return p.ErrorHandler
}
return p.defaultErrorHandler
}
// modifyResponse conditionally runs the optional ModifyResponse hook
// and reports whether the request should proceed.
func (p *ReverseProxy) modifyResponse(rw http.ResponseWriter, res *http.Response, req *http.Request) bool {
if p.ModifyResponse == nil {
return true
}
if err := p.ModifyResponse(res); err != nil {
res.Body.Close()
p.getErrorHandler()(rw, req, err)
return false
}
return true
}
func parseBasicAuth(auth string) (username, password string, ok bool) {
const prefix = "Basic "
// Case insensitive prefix match. See Issue 22736.
if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) {
return
}
c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
if err != nil {
return
}
cs := string(c)
s := strings.IndexByte(cs, ':')
if s < 0 {
return
}
return cs[:s], cs[s+1:], true
}
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
transport = http.DefaultTransport
}
ctx := req.Context()
if cn, ok := rw.(http.CloseNotifier); ok {
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
defer cancel()
notifyChan := cn.CloseNotify()
go func() {
select {
case <-notifyChan:
cancel()
case <-ctx.Done():
}
}()
}
outreq := req.Clone(ctx)
if req.ContentLength == 0 {
outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
}
if outreq.Header == nil {
outreq.Header = make(http.Header) // Issue 33142: historical behavior was to always allocate
}
p.Director(outreq)
outreq.Close = false
reqUpType := upgradeType(outreq.Header)
removeConnectionHeaders(outreq.Header)
// Remove hop-by-hop headers to the backend. Especially
// important is "Connection" because we want a persistent
// connection, regardless of what the client sent to us.
for _, h := range hopHeaders {
hv := outreq.Header.Get(h)
if hv == "" {
continue
}
if h == "Te" && hv == "trailers" {
// Issue 21096: tell backend applications that
// care about trailer support that we support
// trailers. (We do, but we don't go out of
// our way to advertise that unless the
// incoming client request thought it was
// worth mentioning)
continue
}
outreq.Header.Del(h)
}
// After stripping all the hop-by-hop connection headers above, add back any
// necessary for protocol upgrades, such as for websockets.
if reqUpType != "" {
outreq.Header.Set("Connection", "Upgrade")
outreq.Header.Set("Upgrade", reqUpType)
}
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
// If we aren't the first proxy retain prior
// X-Forwarded-For information as a comma+space
// separated list and fold multiple headers into one.
prior, ok := outreq.Header["X-Forwarded-For"]
omit := ok && prior == nil // Issue 38079: nil now means don't populate the header
if len(prior) > 0 {
clientIP = strings.Join(prior, ", ") + ", " + clientIP
}
if !omit {
outreq.Header.Set("X-Forwarded-For", clientIP)
}
}
res, err := transport.RoundTrip(outreq)
if err != nil {
p.getErrorHandler()(rw, outreq, err)
return
}
// Deal with 101 Switching Protocols responses: (WebSocket, h2c, etc)
if res.StatusCode == http.StatusSwitchingProtocols {
if !p.modifyResponse(rw, res, outreq) {
return
}
p.handleUpgradeResponse(rw, outreq, res)
return
}
removeConnectionHeaders(res.Header)
for _, h := range hopHeaders {
res.Header.Del(h)
}
if !p.modifyResponse(rw, res, outreq) {
return
}
copyHeader(rw.Header(), res.Header)
// The "Trailer" header isn't included in the Transport's response,
// at least for *http.Transport. Build it up from Trailer.
announcedTrailers := len(res.Trailer)
if announcedTrailers > 0 {
trailerKeys := make([]string, 0, len(res.Trailer))
for k := range res.Trailer {
trailerKeys = append(trailerKeys, k)
}
rw.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
}
rw.WriteHeader(res.StatusCode)
err = p.copyResponse(rw, res.Body, p.flushInterval(res))
if err != nil {
defer res.Body.Close()
// Since we're streaming the response, if we run into an error all we can do
// is abort the request. Issue 23643: ReverseProxy should use ErrAbortHandler
// on read error while copying body.
if !shouldPanicOnCopyError(req) {
p.logf("suppressing panic for copyResponse error in test; copy error: %v", err)
return
}
panic(http.ErrAbortHandler)
}
res.Body.Close() // close now, instead of defer, to populate res.Trailer
if len(res.Trailer) > 0 {
// Force chunking if we saw a response trailer.
// This prevents net/http from calculating the length for short
// bodies and adding a Content-Length.
if fl, ok := rw.(http.Flusher); ok {
fl.Flush()
}
}
if len(res.Trailer) == announcedTrailers {
copyHeader(rw.Header(), res.Trailer)
return
}
for k, vv := range res.Trailer {
k = http.TrailerPrefix + k
for _, v := range vv {
rw.Header().Add(k, v)
}
}
}
var inOurTests bool // whether we're in our own tests
// shouldPanicOnCopyError reports whether the reverse proxy should
// panic with http.ErrAbortHandler. This is the right thing to do by
// default, but Go 1.10 and earlier did not, so existing unit tests
// weren't expecting panics. Only panic in our own tests, or when
// running under the HTTP server.
func shouldPanicOnCopyError(req *http.Request) bool {
if inOurTests {
// Our tests know to handle this panic.
return true
}
if req.Context().Value(http.ServerContextKey) != nil {
// We seem to be running under an HTTP server, so
// it'll recover the panic.
return true
}
// Otherwise act like Go 1.10 and earlier to not break
// existing tests.
return false
}
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.
// See RFC 7230, section 6.1
func removeConnectionHeaders(h http.Header) {
for _, f := range h["Connection"] {
for _, sf := range strings.Split(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
h.Del(sf)
}
}
}
}
// flushInterval returns the p.FlushInterval value, conditionally
// overriding its value for a specific request/response.
func (p *ReverseProxy) flushInterval(res *http.Response) time.Duration {
resCT := res.Header.Get("Content-Type")
// For Server-Sent Events responses, flush immediately.
// The MIME type is defined in https://www.w3.org/TR/eventsource/#text-event-stream
if resCT == "text/event-stream" {
return -1 // negative means immediately
}
// We might have the case of streaming for which Content-Length might be unset.
if res.ContentLength == -1 {
return -1
}
return p.FlushInterval
}
func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval time.Duration) error {
if flushInterval != 0 {
if wf, ok := dst.(writeFlusher); ok {
mlw := &maxLatencyWriter{
dst: wf,
latency: flushInterval,
}
defer mlw.stop()
// set up initial timer so headers get flushed even if body writes are delayed
mlw.flushPending = true
mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
dst = mlw
}
}
var buf []byte
if p.BufferPool != nil {
buf = p.BufferPool.Get()
defer p.BufferPool.Put(buf)
}
_, err := p.copyBuffer(dst, src, buf)
return err
}
// copyBuffer returns any write errors or non-EOF read errors, and the amount
// of bytes written.
func (p *ReverseProxy) copyBuffer(dst io.Writer, src io.Reader, buf []byte) (int64, error) {
if len(buf) == 0 {
buf = make([]byte, 32*1024)
}
var written int64
for {
nr, rerr := src.Read(buf)
if rerr != nil && rerr != io.EOF && rerr != context.Canceled {
p.logf("httputil: ReverseProxy read error during body copy: %v", rerr)
}
if nr > 0 {
nw, werr := dst.Write(buf[:nr])
if nw > 0 {
written += int64(nw)
}
if werr != nil {
return written, werr
}
if nr != nw {
return written, io.ErrShortWrite
}
}
if rerr != nil {
if rerr == io.EOF {
rerr = nil
}
return written, rerr
}
}
}
func (p *ReverseProxy) logf(format string, args ...interface{}) {
if p.ErrorLog != nil {
p.ErrorLog.Printf(format, args...)
} else {
log.Printf(format, args...)
}
}
type writeFlusher interface {
io.Writer
http.Flusher
}
type maxLatencyWriter struct {
dst writeFlusher
latency time.Duration // non-zero; negative means to flush immediately
mu sync.Mutex // protects t, flushPending, and dst.Flush
t *time.Timer
flushPending bool
}
func (m *maxLatencyWriter) Write(p []byte) (n int, err error) {
m.mu.Lock()
defer m.mu.Unlock()
n, err = m.dst.Write(p)
if m.latency < 0 {
m.dst.Flush()
return
}
if m.flushPending {
return
}
if m.t == nil {
m.t = time.AfterFunc(m.latency, m.delayedFlush)
} else {
m.t.Reset(m.latency)
}
m.flushPending = true
return
}
func (m *maxLatencyWriter) delayedFlush() {
m.mu.Lock()
defer m.mu.Unlock()
if !m.flushPending { // if stop was called but AfterFunc already started this goroutine
return
}
m.dst.Flush()
m.flushPending = false
}
func (m *maxLatencyWriter) stop() {
m.mu.Lock()
defer m.mu.Unlock()
m.flushPending = false
if m.t != nil {
m.t.Stop()
}
}
func upgradeType(h http.Header) string {
if !httpguts.HeaderValuesContainsToken(h["Connection"], "Upgrade") {
return ""
}
return strings.ToLower(h.Get("Upgrade"))
}
func (p *ReverseProxy) handleUpgradeResponse(rw http.ResponseWriter, req *http.Request, res *http.Response) {
reqUpType := upgradeType(req.Header)
resUpType := upgradeType(res.Header)
if reqUpType != resUpType {
p.getErrorHandler()(rw, req, fmt.Errorf("backend tried to switch protocol %q when %q was requested", resUpType, reqUpType))
return
}
hj, ok := rw.(http.Hijacker)
if !ok {
p.getErrorHandler()(rw, req, fmt.Errorf("can't switch protocols using non-Hijacker ResponseWriter type %T", rw))
return
}
backConn, ok := res.Body.(io.ReadWriteCloser)
if !ok {
p.getErrorHandler()(rw, req, fmt.Errorf("internal error: 101 switching protocols response with non-writable body"))
return
}
backConnCloseCh := make(chan bool)
go func() {
// Ensure that the cancelation of a request closes the backend.
// See issue https://golang.org/issue/35559.
select {
case <-req.Context().Done():
case <-backConnCloseCh:
}
backConn.Close()
}()
defer close(backConnCloseCh)
conn, brw, err := hj.Hijack()
if err != nil {
p.getErrorHandler()(rw, req, fmt.Errorf("Hijack failed on protocol switch: %v", err))
return
}
defer conn.Close()
copyHeader(rw.Header(), res.Header)
res.Header = rw.Header()
res.Body = nil // so res.Write only writes the headers; we have res.Body in backConn above
if err := res.Write(brw); err != nil {
p.getErrorHandler()(rw, req, fmt.Errorf("response write: %v", err))
return
}
if err := brw.Flush(); err != nil {
p.getErrorHandler()(rw, req, fmt.Errorf("response flush: %v", err))
return
}
errc := make(chan error, 1)
spc := switchProtocolCopier{user: conn, backend: backConn}
go spc.copyToBackend(errc)
go spc.copyFromBackend(errc)
<-errc
return
}
// switchProtocolCopier exists so goroutines proxying data back and
// forth have nice names in stacks.
type switchProtocolCopier struct {
user, backend io.ReadWriter
}
func (c switchProtocolCopier) copyFromBackend(errc chan<- error) {
_, err := io.Copy(c.user, c.backend)
errc <- err
}
func (c switchProtocolCopier) copyToBackend(errc chan<- error) {
_, err := io.Copy(c.backend, c.user)
errc <- err
}

View File

@ -7,9 +7,7 @@ import (
"sync" "sync"
) )
var ( var ErrRouterConfigConflict = errors.New("router config conflict")
ErrRouterConfigConflict = errors.New("router config conflict")
)
type routerByHTTPUser map[string][]*Router type routerByHTTPUser map[string][]*Router
@ -133,9 +131,11 @@ type ByLocation []*Router
func (a ByLocation) Len() int { func (a ByLocation) Len() int {
return len(a) return len(a)
} }
func (a ByLocation) Swap(i, j int) { func (a ByLocation) Swap(i, j int) {
a[i], a[j] = a[j], a[i] a[i], a[j] = a[j], a[i]
} }
func (a ByLocation) Less(i, j int) bool { func (a ByLocation) Less(i, j int) bool {
return strings.Compare(a[i].location, a[j].location) < 0 return strings.Compare(a[i].location, a[j].location) < 0
} }

View File

@ -19,11 +19,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/fatedier/golib/errors"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/golib/errors"
) )
type RouteInfo string type RouteInfo string
@ -36,10 +36,12 @@ const (
RouteInfoURLHost RouteInfo = "urlHost" RouteInfoURLHost RouteInfo = "urlHost"
) )
type muxFunc func(net.Conn) (net.Conn, map[string]string, error) type (
type httpAuthFunc func(net.Conn, string, string, string) (bool, error) muxFunc func(net.Conn) (net.Conn, map[string]string, error)
type hostRewriteFunc func(net.Conn, string) (net.Conn, error) httpAuthFunc func(net.Conn, string, string, string) (bool, error)
type successFunc func(net.Conn, map[string]string) error hostRewriteFunc func(net.Conn, string) (net.Conn, error)
successFunc func(net.Conn, map[string]string) error
)
// Muxer is only used for https and tcpmux proxy. // Muxer is only used for https and tcpmux proxy.
type Muxer struct { type Muxer struct {
@ -60,7 +62,6 @@ func NewMuxer(
rewriteFunc hostRewriteFunc, rewriteFunc hostRewriteFunc,
timeout time.Duration, timeout time.Duration,
) (mux *Muxer, err error) { ) (mux *Muxer, err error) {
mux = &Muxer{ mux = &Muxer{
listener: listener, listener: listener,
timeout: timeout, timeout: timeout,
@ -111,9 +112,8 @@ func (v *Muxer) Listen(ctx context.Context, cfg *RouteConfig) (l *Listener, err
} }
func (v *Muxer) getListener(name, path, httpUser string) (*Listener, bool) { func (v *Muxer) getListener(name, path, httpUser string) (*Listener, bool) {
findRouter := func(inName, inPath, inHTTPUser string) (*Listener, bool) { findRouter := func(inName, inPath, inHTTPUser string) (*Listener, bool) {
vr, ok := v.registryRouter.Get(inName, inPath, httpUser) vr, ok := v.registryRouter.Get(inName, inPath, inHTTPUser)
if ok { if ok {
return vr.payload.(*Listener), true return vr.payload.(*Listener), true
} }
@ -167,14 +167,14 @@ func (v *Muxer) run() {
func (v *Muxer) handle(c net.Conn) { func (v *Muxer) 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
} }
sConn, reqInfoMap, err := v.vhostFunc(c) sConn, reqInfoMap, err := v.vhostFunc(c)
if err != nil { if err != nil {
log.Debug("get hostname from http/https request error: %v", err) log.Debug("get hostname from http/https request error: %v", err)
c.Close() _ = c.Close()
return return
} }
@ -184,9 +184,12 @@ func (v *Muxer) handle(c net.Conn) {
l, ok := v.getListener(name, path, httpUser) l, ok := v.getListener(name, path, httpUser)
if !ok { if !ok {
res := notFoundResponse() res := notFoundResponse()
res.Write(c) if res.Body != nil {
defer res.Body.Close()
}
_ = res.Write(c)
log.Debug("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser) log.Debug("http request for host [%s] path [%s] httpUser [%s] not found", name, path, httpUser)
c.Close() _ = c.Close()
return return
} }
@ -194,7 +197,7 @@ func (v *Muxer) handle(c net.Conn) {
if v.successFunc != nil { if v.successFunc != nil {
if err := v.successFunc(c, reqInfoMap); err != nil { if err := v.successFunc(c, reqInfoMap); err != nil {
xl.Info("success func failure on vhost connection: %v", err) xl.Info("success func failure on vhost connection: %v", err)
c.Close() _ = c.Close()
return return
} }
} }
@ -203,17 +206,20 @@ func (v *Muxer) handle(c net.Conn) {
// 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 || err != nil {
xl.Debug("check http Authorization failed") xl.Debug("check http Authorization failed")
res := noAuthResponse() res := noAuthResponse()
res.Write(c) if res.Body != nil {
c.Close() defer res.Body.Close()
}
_ = res.Write(c)
_ = c.Close()
return return
} }
} }
if err = sConn.SetDeadline(time.Time{}); err != nil { if err = sConn.SetDeadline(time.Time{}); err != nil {
c.Close() _ = c.Close()
return return
} }
c = sConn c = sConn

View File

@ -23,6 +23,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/fatedier/golib/control/shutdown"
"github.com/fatedier/golib/crypto"
"github.com/fatedier/golib/errors"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
@ -35,10 +39,6 @@ import (
"github.com/fatedier/frp/server/controller" "github.com/fatedier/frp/server/controller"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
"github.com/fatedier/frp/server/proxy" "github.com/fatedier/frp/server/proxy"
"github.com/fatedier/golib/control/shutdown"
"github.com/fatedier/golib/crypto"
"github.com/fatedier/golib/errors"
) )
type ControlManager struct { type ControlManager struct {
@ -154,7 +154,6 @@ func NewControl(
loginMsg *msg.Login, loginMsg *msg.Login,
serverCfg config.ServerCommonConf, serverCfg config.ServerCommonConf,
) *Control { ) *Control {
poolCount := loginMsg.PoolCount poolCount := loginMsg.PoolCount
if poolCount > int(serverCfg.MaxPoolCount) { if poolCount > int(serverCfg.MaxPoolCount) {
poolCount = int(serverCfg.MaxPoolCount) poolCount = int(serverCfg.MaxPoolCount)
@ -193,7 +192,7 @@ func (ctl *Control) Start() {
ServerUDPPort: ctl.serverCfg.BindUDPPort, ServerUDPPort: ctl.serverCfg.BindUDPPort,
Error: "", Error: "",
} }
msg.WriteMsg(ctl.conn, loginRespMsg) _ = msg.WriteMsg(ctl.conn, loginRespMsg)
go ctl.writer() go ctl.writer()
for i := 0; i < ctl.poolCount; i++ { for i := 0; i < ctl.poolCount; i++ {
@ -270,7 +269,7 @@ func (ctl *Control) GetWorkConn() (workConn net.Conn, err error) {
} }
// When we get a work connection from pool, replace it with a new one. // When we get a work connection from pool, replace it with a new one.
errors.PanicToError(func() { _ = errors.PanicToError(func() {
ctl.sendCh <- &msg.ReqWorkConn{} ctl.sendCh <- &msg.ReqWorkConn{}
}) })
return return
@ -388,7 +387,7 @@ func (ctl *Control) stoper() {
}, },
} }
go func() { go func() {
ctl.pluginManager.CloseProxy(notifyContent) _ = ctl.pluginManager.CloseProxy(notifyContent)
}() }()
} }
@ -467,7 +466,7 @@ func (ctl *Control) manager() {
} }
ctl.sendCh <- resp ctl.sendCh <- resp
case *msg.CloseProxy: case *msg.CloseProxy:
ctl.CloseProxy(m) _ = ctl.CloseProxy(m)
xl.Info("close proxy [%s] success", m.ProxyName) xl.Info("close proxy [%s] success", m.ProxyName)
case *msg.Ping: case *msg.Ping:
content := &plugin.PingContent{ content := &plugin.PingContent{
@ -528,13 +527,13 @@ func (ctl *Control) RegisterProxy(pxyMsg *msg.NewProxy) (remoteAddr string, err
err = fmt.Errorf("exceed the max_ports_per_client") err = fmt.Errorf("exceed the max_ports_per_client")
return return
} }
ctl.portsUsedNum = ctl.portsUsedNum + pxy.GetUsedPortsNum() ctl.portsUsedNum += pxy.GetUsedPortsNum()
ctl.mu.Unlock() ctl.mu.Unlock()
defer func() { defer func() {
if err != nil { if err != nil {
ctl.mu.Lock() ctl.mu.Lock()
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum() ctl.portsUsedNum -= pxy.GetUsedPortsNum()
ctl.mu.Unlock() ctl.mu.Unlock()
} }
}() }()
@ -570,7 +569,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
} }
if ctl.serverCfg.MaxPortsPerClient > 0 { if ctl.serverCfg.MaxPortsPerClient > 0 {
ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum() ctl.portsUsedNum -= pxy.GetUsedPortsNum()
} }
pxy.Close() pxy.Close()
ctl.pxyManager.Del(pxy.GetName()) ctl.pxyManager.Del(pxy.GetName())
@ -590,7 +589,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
}, },
} }
go func() { go func() {
ctl.pluginManager.CloseProxy(notifyContent) _ = ctl.pluginManager.CloseProxy(notifyContent)
}() }()
return return

View File

@ -21,11 +21,11 @@ import (
"net/http/pprof" "net/http/pprof"
"time" "time"
"github.com/fatedier/frp/assets"
frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/fatedier/frp/assets"
frpNet "github.com/fatedier/frp/pkg/util/net"
) )
var ( var (
@ -92,6 +92,8 @@ func (svr *Service) RunDashboardServer(address string) (err error) {
} }
ln = tls.NewListener(ln, tlsCfg) ln = tls.NewListener(ln, tlsCfg)
} }
go server.Serve(ln) go func() {
_ = server.Serve(ln)
}()
return return
} }

View File

@ -18,13 +18,13 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/gorilla/mux"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/metrics/mem" "github.com/fatedier/frp/pkg/metrics/mem"
"github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/pkg/util/version"
"github.com/gorilla/mux"
) )
type GeneralResponse struct { type GeneralResponse struct {
@ -63,7 +63,7 @@ func (svr *Service) APIServerInfo(w http.ResponseWriter, r *http.Request) {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
@ -179,7 +179,7 @@ func (svr *Service) APIProxyByType(w http.ResponseWriter, r *http.Request) {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Info("Http request: [%s]", r.URL.Path)
@ -245,12 +245,12 @@ func (svr *Service) APIProxyByTypeAndName(w http.ResponseWriter, r *http.Request
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Info("Http request: [%s]", r.URL.Path)
proxyStatsResp := GetProxyStatsResp{} var proxyStatsResp GetProxyStatsResp
proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name) proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
if res.Code != 200 { if res.Code != 200 {
return return
@ -313,7 +313,7 @@ func (svr *Service) APIProxyTraffic(w http.ResponseWriter, r *http.Request) {
log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code) log.Info("Http response [%s]: code [%d]", r.URL.Path, res.Code)
w.WriteHeader(res.Code) w.WriteHeader(res.Code)
if len(res.Msg) > 0 { if len(res.Msg) > 0 {
w.Write([]byte(res.Msg)) _, _ = w.Write([]byte(res.Msg))
} }
}() }()
log.Info("Http request: [%s]", r.URL.Path) log.Info("Http request: [%s]", r.URL.Path)

View File

@ -31,7 +31,6 @@ func (ctl *HTTPGroupController) Register(
proxyName, group, groupKey string, proxyName, group, groupKey string,
routeConfig vhost.RouteConfig, routeConfig vhost.RouteConfig,
) (err error) { ) (err error) {
indexKey := group indexKey := group
ctl.mu.Lock() ctl.mu.Lock()
g, ok := ctl.groups[indexKey] g, ok := ctl.groups[indexKey]
@ -86,7 +85,6 @@ func (g *HTTPGroup) Register(
proxyName, group, groupKey string, proxyName, group, groupKey string,
routeConfig vhost.RouteConfig, routeConfig vhost.RouteConfig,
) (err error) { ) (err error) {
g.mu.Lock() g.mu.Lock()
defer g.mu.Unlock() defer g.mu.Unlock()
if len(g.createFuncs) == 0 { if len(g.createFuncs) == 0 {
@ -152,7 +150,7 @@ func (g *HTTPGroup) createConn(remoteAddr string) (net.Conn, error) {
routeByHTTPUser := g.routeByHTTPUser routeByHTTPUser := g.routeByHTTPUser
if len(g.pxyNames) > 0 { if len(g.pxyNames) > 0 {
name := g.pxyNames[int(newIndex)%len(g.pxyNames)] name := g.pxyNames[int(newIndex)%len(g.pxyNames)]
f, _ = g.createFuncs[name] f = g.createFuncs[name]
} }
g.mu.RUnlock() g.mu.RUnlock()

View File

@ -19,9 +19,9 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/fatedier/frp/server/ports"
gerr "github.com/fatedier/golib/errors" gerr "github.com/fatedier/golib/errors"
"github.com/fatedier/frp/server/ports"
) )
// TCPGroupCtl manage all TCPGroups // TCPGroupCtl manage all TCPGroups
@ -44,8 +44,8 @@ func NewTCPGroupCtl(portManager *ports.Manager) *TCPGroupCtl {
// Listen is the wrapper for TCPGroup's Listen // Listen is the wrapper for TCPGroup's Listen
// If there are no group, we will create one here // If there are no group, we will create one here
func (tgc *TCPGroupCtl) Listen(proxyName string, group string, groupKey string, func (tgc *TCPGroupCtl) Listen(proxyName string, group string, groupKey string,
addr string, port int) (l net.Listener, realPort int, err error) { addr string, port int,
) (l net.Listener, realPort int, err error) {
tgc.mu.Lock() tgc.mu.Lock()
tcpGroup, ok := tgc.groups[group] tcpGroup, ok := tgc.groups[group]
if !ok { if !ok {
@ -73,7 +73,6 @@ type TCPGroup struct {
realPort int realPort int
acceptCh chan net.Conn acceptCh chan net.Conn
index uint64
tcpLn net.Listener tcpLn net.Listener
lns []*TCPGroupListener lns []*TCPGroupListener
ctl *TCPGroupCtl ctl *TCPGroupCtl

View File

@ -20,11 +20,11 @@ import (
"net" "net"
"sync" "sync"
gerr "github.com/fatedier/golib/errors"
"github.com/fatedier/frp/pkg/consts" "github.com/fatedier/frp/pkg/consts"
"github.com/fatedier/frp/pkg/util/tcpmux" "github.com/fatedier/frp/pkg/util/tcpmux"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
gerr "github.com/fatedier/golib/errors"
) )
// TCPMuxGroupCtl manage all TCPMuxGroups // TCPMuxGroupCtl manage all TCPMuxGroups
@ -51,7 +51,6 @@ func (tmgc *TCPMuxGroupCtl) Listen(
multiplexer, group, groupKey string, multiplexer, group, groupKey string,
routeConfig vhost.RouteConfig, routeConfig vhost.RouteConfig,
) (l net.Listener, err error) { ) (l net.Listener, err error) {
tmgc.mu.Lock() tmgc.mu.Lock()
tcpMuxGroup, ok := tmgc.groups[group] tcpMuxGroup, ok := tmgc.groups[group]
if !ok { if !ok {
@ -84,7 +83,6 @@ type TCPMuxGroup struct {
routeByHTTPUser string routeByHTTPUser string
acceptCh chan net.Conn acceptCh chan net.Conn
index uint64
tcpMuxLn net.Listener tcpMuxLn net.Listener
lns []*TCPMuxGroupListener lns []*TCPMuxGroupListener
ctl *TCPMuxGroupCtl ctl *TCPMuxGroupCtl
@ -108,7 +106,6 @@ func (tmg *TCPMuxGroup) HTTPConnectListen(
group, groupKey string, group, groupKey string,
routeConfig vhost.RouteConfig, routeConfig vhost.RouteConfig,
) (ln *TCPMuxGroupListener, err error) { ) (ln *TCPMuxGroupListener, err error) {
tmg.mu.Lock() tmg.mu.Lock()
defer tmg.mu.Unlock() defer tmg.mu.Unlock()
if len(tmg.lns) == 0 { if len(tmg.lns) == 0 {

View File

@ -19,13 +19,13 @@ import (
"net" "net"
"strings" "strings"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
"github.com/fatedier/frp/pkg/util/vhost" "github.com/fatedier/frp/pkg/util/vhost"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
frpIo "github.com/fatedier/golib/io"
) )
type HTTPProxy struct { type HTTPProxy struct {
@ -89,7 +89,7 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
pxy.rc.HTTPReverseProxy.UnRegister(tmpRouteConfig) pxy.rc.HTTPReverseProxy.UnRegister(tmpRouteConfig)
}) })
} }
addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, int(pxy.serverCfg.VhostHTTPPort))) addrs = append(addrs, util.CanonicalAddr(routeConfig.Domain, pxy.serverCfg.VhostHTTPPort))
xl.Info("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]", xl.Info("http proxy listen for host [%s] location [%s] group [%s], routeByHTTPUser [%s]",
routeConfig.Domain, routeConfig.Location, pxy.cfg.Group, pxy.cfg.RouteByHTTPUser) routeConfig.Domain, routeConfig.Location, pxy.cfg.Group, pxy.cfg.RouteByHTTPUser)
} }

View File

@ -62,7 +62,7 @@ func (pxy *HTTPSProxy) Run() (remoteAddr string, err error) {
} }
xl.Info("https proxy listen for host [%s]", routeConfig.Domain) xl.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, pxy.serverCfg.VhostHTTPSPort))
} }
pxy.startListenHandler(pxy, HandleUserTCPConnection) pxy.startListenHandler(pxy, HandleUserTCPConnection)

View File

@ -23,6 +23,8 @@ import (
"sync" "sync"
"time" "time"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
plugin "github.com/fatedier/frp/pkg/plugin/server" plugin "github.com/fatedier/frp/pkg/plugin/server"
@ -30,8 +32,6 @@ import (
"github.com/fatedier/frp/pkg/util/xlog" "github.com/fatedier/frp/pkg/util/xlog"
"github.com/fatedier/frp/server/controller" "github.com/fatedier/frp/server/controller"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
frpIo "github.com/fatedier/golib/io"
) )
type GetWorkConnFn func() (net.Conn, error) type GetWorkConnFn func() (net.Conn, error)
@ -184,8 +184,8 @@ func (pxy *BaseProxy) startListenHandler(p Proxy, handler func(Proxy, net.Conn,
} }
func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, poolCount int, func NewProxy(ctx context.Context, userInfo plugin.UserInfo, rc *controller.ResourceController, 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) xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName)
basePxy := BaseProxy{ basePxy := BaseProxy{
name: pxyConf.GetBaseInfo().ProxyName, name: pxyConf.GetBaseInfo().ProxyName,

View File

@ -22,14 +22,14 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/frp/pkg/proto/udp" "github.com/fatedier/frp/pkg/proto/udp"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/server/metrics" "github.com/fatedier/frp/server/metrics"
"github.com/fatedier/golib/errors"
frpIo "github.com/fatedier/golib/io"
) )
type UDPProxy struct { type UDPProxy struct {
@ -98,18 +98,20 @@ func (pxy *UDPProxy) Run() (remoteAddr string, err error) {
) )
xl.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 {
xl.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
errors.PanicToError(func() { _ = errors.PanicToError(func() {
pxy.checkCloseCh <- 1 pxy.checkCloseCh <- 1
}) })
return return
} }
conn.SetReadDeadline(time.Time{}) if err := conn.SetReadDeadline(time.Time{}); err != nil {
xl.Warn("set read deadline error: %v", err)
}
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.Ping: case *msg.Ping:
xl.Trace("udp work conn get ping message") xl.Trace("udp work conn get ping message")

View File

@ -17,10 +17,10 @@ package proxy
import ( import (
"fmt" "fmt"
"github.com/fatedier/golib/errors"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
"github.com/fatedier/frp/pkg/msg" "github.com/fatedier/frp/pkg/msg"
"github.com/fatedier/golib/errors"
) )
type XTCPProxy struct { type XTCPProxy struct {
@ -91,7 +91,7 @@ func (pxy *XTCPProxy) GetConf() config.ProxyConf {
func (pxy *XTCPProxy) Close() { func (pxy *XTCPProxy) Close() {
pxy.BaseProxy.Close() pxy.BaseProxy.Close()
pxy.rc.NatHoleController.CloseClient(pxy.GetName()) pxy.rc.NatHoleController.CloseClient(pxy.GetName())
errors.PanicToError(func() { _ = errors.PanicToError(func() {
close(pxy.closeCh) close(pxy.closeCh)
}) })
} }

View File

@ -26,6 +26,9 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/fatedier/golib/net/mux"
fmux "github.com/hashicorp/yamux"
"github.com/fatedier/frp/assets" "github.com/fatedier/frp/assets"
"github.com/fatedier/frp/pkg/auth" "github.com/fatedier/frp/pkg/auth"
"github.com/fatedier/frp/pkg/config" "github.com/fatedier/frp/pkg/config"
@ -47,9 +50,6 @@ import (
"github.com/fatedier/frp/server/ports" "github.com/fatedier/frp/server/ports"
"github.com/fatedier/frp/server/proxy" "github.com/fatedier/frp/server/proxy"
"github.com/fatedier/frp/server/visitor" "github.com/fatedier/frp/server/visitor"
"github.com/fatedier/golib/net/mux"
fmux "github.com/hashicorp/yamux"
) )
const ( const (
@ -127,26 +127,26 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort)) address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
l, err = net.Listen("tcp", address) l, err = net.Listen("tcp", address)
if err != nil { if err != nil {
err = fmt.Errorf("Create server listener error, %v", err) err = fmt.Errorf("create server listener error, %v", err)
return return
} }
svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout) svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
if err != nil { if err != nil {
err = fmt.Errorf("Create vhost tcpMuxer error, %v", err) err = fmt.Errorf("create vhost tcpMuxer error, %v", err)
return return
} }
log.Info("tcpmux httpconnect multiplexer listen on %s, passthough: %v", address, cfg.TCPMuxPassthrough) log.Info("tcpmux httpconnect multiplexer listen on %s, passthough: %v", address, cfg.TCPMuxPassthrough)
} }
// Init all plugins // Init all plugins
plugin_names := make([]string, 0, len(cfg.HTTPPlugins)) pluginNames := make([]string, 0, len(cfg.HTTPPlugins))
for n := range cfg.HTTPPlugins { for n := range cfg.HTTPPlugins {
plugin_names = append(plugin_names, n) pluginNames = append(pluginNames, n)
} }
sort.Strings(plugin_names) sort.Strings(pluginNames)
for _, name := range plugin_names { for _, name := range pluginNames {
svr.pluginManager.Register(plugin.NewHTTPPluginOptions(cfg.HTTPPlugins[name])) svr.pluginManager.Register(plugin.NewHTTPPluginOptions(cfg.HTTPPlugins[name]))
log.Info("plugin [%s] has been registered", name) log.Info("plugin [%s] has been registered", name)
} }
@ -181,13 +181,15 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.BindPort)) address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.BindPort))
ln, err := net.Listen("tcp", address) ln, err := net.Listen("tcp", address)
if err != nil { if err != nil {
err = fmt.Errorf("Create server listener error, %v", err) err = fmt.Errorf("create server listener error, %v", err)
return return
} }
svr.muxer = mux.NewMux(ln) svr.muxer = mux.NewMux(ln)
svr.muxer.SetKeepAlive(time.Duration(cfg.TCPKeepAlive) * time.Second) svr.muxer.SetKeepAlive(time.Duration(cfg.TCPKeepAlive) * time.Second)
go svr.muxer.Serve() go func() {
_ = svr.muxer.Serve()
}()
ln = svr.muxer.DefaultListener() ln = svr.muxer.DefaultListener()
svr.listener = ln svr.listener = ln
@ -198,7 +200,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.KCPBindPort)) address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.KCPBindPort))
svr.kcpListener, err = frpNet.ListenKcp(address) svr.kcpListener, err = frpNet.ListenKcp(address)
if err != nil { if err != nil {
err = fmt.Errorf("Listen on kcp address udp %s error: %v", address, err) err = fmt.Errorf("listen on kcp address udp %s error: %v", address, err)
return return
} }
log.Info("frps kcp listen on udp %s", address) log.Info("frps kcp listen on udp %s", address)
@ -229,11 +231,13 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
} else { } else {
l, err = net.Listen("tcp", address) l, err = net.Listen("tcp", address)
if err != nil { if err != nil {
err = fmt.Errorf("Create vhost http listener error, %v", err) err = fmt.Errorf("create vhost http listener error, %v", err)
return return
} }
} }
go server.Serve(l) go func() {
_ = server.Serve(l)
}()
log.Info("http service listen on %s", address) log.Info("http service listen on %s", address)
} }
@ -246,7 +250,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort)) address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.VhostHTTPSPort))
l, err = net.Listen("tcp", address) l, err = net.Listen("tcp", address)
if err != nil { if err != nil {
err = fmt.Errorf("Create server listener error, %v", err) err = fmt.Errorf("create server listener error, %v", err)
return return
} }
log.Info("https service listen on %s", address) log.Info("https service listen on %s", address)
@ -254,7 +258,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
svr.rc.VhostHTTPSMuxer, err = vhost.NewHTTPSMuxer(l, vhostReadWriteTimeout) svr.rc.VhostHTTPSMuxer, err = vhost.NewHTTPSMuxer(l, vhostReadWriteTimeout)
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
} }
} }
@ -271,7 +275,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.BindUDPPort)) address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.BindUDPPort))
nc, err = nathole.NewController(address) nc, err = nathole.NewController(address)
if err != nil { if err != nil {
err = fmt.Errorf("Create nat hole controller error, %v", err) err = fmt.Errorf("create nat hole controller error, %v", err)
return return
} }
svr.rc.NatHoleController = nc svr.rc.NatHoleController = nc
@ -287,7 +291,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
address := net.JoinHostPort(cfg.DashboardAddr, strconv.Itoa(cfg.DashboardPort)) address := net.JoinHostPort(cfg.DashboardAddr, strconv.Itoa(cfg.DashboardPort))
err = svr.RunDashboardServer(address) err = svr.RunDashboardServer(address)
if err != nil { if err != nil {
err = fmt.Errorf("Create dashboard web server error, %v", err) err = fmt.Errorf("create dashboard web server error, %v", err)
return return
} }
log.Info("Dashboard listen on %s", address) log.Info("Dashboard listen on %s", address)
@ -324,13 +328,13 @@ func (svr *Service) handleConnection(ctx context.Context, conn net.Conn) {
err error err error
) )
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 {
log.Trace("Failed to read message: %v", err) log.Trace("Failed to read message: %v", err)
conn.Close() conn.Close()
return return
} }
conn.SetReadDeadline(time.Time{}) _ = conn.SetReadDeadline(time.Time{})
switch m := rawMsg.(type) { switch m := rawMsg.(type) {
case *msg.Login: case *msg.Login:
@ -349,7 +353,7 @@ func (svr *Service) handleConnection(ctx context.Context, conn net.Conn) {
// Otherwise send success message in control's work goroutine. // Otherwise send success message in control's work goroutine.
if err != nil { if err != nil {
xl.Warn("register control error: %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: util.GenerateResponseErrorString("register control error", err, svr.cfg.DetailedErrorsToClient), Error: util.GenerateResponseErrorString("register control error", err, svr.cfg.DetailedErrorsToClient),
}) })
@ -362,13 +366,13 @@ func (svr *Service) handleConnection(ctx context.Context, conn net.Conn) {
case *msg.NewVisitorConn: case *msg.NewVisitorConn:
if err = svr.RegisterVisitorConn(conn, m); err != nil { if err = svr.RegisterVisitorConn(conn, m); err != nil {
xl.Warn("register visitor conn error: %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: util.GenerateResponseErrorString("register visitor conn error", err, svr.cfg.DetailedErrorsToClient), Error: util.GenerateResponseErrorString("register visitor conn error", err, svr.cfg.DetailedErrorsToClient),
}) })
conn.Close() conn.Close()
} else { } else {
msg.WriteMsg(conn, &msg.NewVisitorConnResp{ _ = msg.WriteMsg(conn, &msg.NewVisitorConnResp{
ProxyName: m.ProxyName, ProxyName: m.ProxyName,
Error: "", Error: "",
}) })
@ -504,7 +508,7 @@ func (svr *Service) RegisterWorkConn(workConn net.Conn, newMsg *msg.NewWorkConn)
} }
if err != nil { if err != nil {
xl.Warn("invalid NewWorkConn with run id [%s]", newMsg.RunID) xl.Warn("invalid NewWorkConn with run id [%s]", newMsg.RunID)
msg.WriteMsg(workConn, &msg.StartWorkConn{ _ = msg.WriteMsg(workConn, &msg.StartWorkConn{
Error: util.GenerateResponseErrorString("invalid NewWorkConn", err, ctl.serverCfg.DetailedErrorsToClient), Error: util.GenerateResponseErrorString("invalid NewWorkConn", err, ctl.serverCfg.DetailedErrorsToClient),
}) })
return fmt.Errorf("invalid NewWorkConn with run id [%s]", newMsg.RunID) return fmt.Errorf("invalid NewWorkConn with run id [%s]", newMsg.RunID)

View File

@ -20,10 +20,10 @@ import (
"net" "net"
"sync" "sync"
frpIo "github.com/fatedier/golib/io"
frpNet "github.com/fatedier/frp/pkg/util/net" frpNet "github.com/fatedier/frp/pkg/util/net"
"github.com/fatedier/frp/pkg/util/util" "github.com/fatedier/frp/pkg/util/util"
frpIo "github.com/fatedier/golib/io"
) )
// Manager for visitor listeners. // Manager for visitor listeners.
@ -57,8 +57,8 @@ func (vm *Manager) Listen(name string, sk string) (l *frpNet.CustomListener, err
} }
func (vm *Manager) NewConn(name string, conn net.Conn, timestamp int64, signKey string, func (vm *Manager) 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()
defer vm.mu.RUnlock() defer vm.mu.RUnlock()

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/pkg/transport" "github.com/fatedier/frp/pkg/transport"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
@ -12,18 +14,16 @@ import (
"github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
"github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/port"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: Basic]", func() { var _ = ginkgo.Describe("[Feature: Basic]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
Describe("TCP && UDP", func() { ginkgo.Describe("TCP && UDP", func() {
types := []string{"tcp", "udp"} types := []string{"tcp", "udp"}
for _, t := range types { for _, t := range types {
proxyType := t proxyType := t
It(fmt.Sprintf("Expose a %s echo server", strings.ToUpper(proxyType)), func() { ginkgo.It(fmt.Sprintf("Expose a %s echo server", strings.ToUpper(proxyType)), func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -93,8 +93,8 @@ var _ = Describe("[Feature: Basic]", func() {
} }
}) })
Describe("HTTP", func() { ginkgo.Describe("HTTP", func() {
It("proxy to HTTP server", func() { ginkgo.It("proxy to HTTP server", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf += fmt.Sprintf(` serverConf += fmt.Sprintf(`
@ -175,8 +175,8 @@ var _ = Describe("[Feature: Basic]", func() {
}) })
}) })
Describe("HTTPS", func() { ginkgo.Describe("HTTPS", func() {
It("proxy to HTTPS server", func() { ginkgo.It("proxy to HTTPS server", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
vhostHTTPSPort := f.AllocPort() vhostHTTPSPort := f.AllocPort()
serverConf += fmt.Sprintf(` serverConf += fmt.Sprintf(`
@ -237,7 +237,7 @@ var _ = Describe("[Feature: Basic]", func() {
framework.ExpectNoError(err) framework.ExpectNoError(err)
localServer := httpserver.New( localServer := httpserver.New(
httpserver.WithBindPort(localPort), httpserver.WithBindPort(localPort),
httpserver.WithTlsConfig(tlsConfig), httpserver.WithTLSConfig(tlsConfig),
httpserver.WithResponse([]byte("test")), httpserver.WithResponse([]byte("test")),
) )
f.RunServer("", localServer) f.RunServer("", localServer)
@ -275,11 +275,11 @@ var _ = Describe("[Feature: Basic]", func() {
}) })
}) })
Describe("STCP && SUDP", func() { ginkgo.Describe("STCP && SUDP", func() {
types := []string{"stcp", "sudp"} types := []string{"stcp", "sudp"}
for _, t := range types { for _, t := range types {
proxyType := t proxyType := t
It(fmt.Sprintf("Expose echo server with %s", strings.ToUpper(proxyType)), func() { ginkgo.It(fmt.Sprintf("Expose echo server with %s", strings.ToUpper(proxyType)), func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientServerConf := consts.DefaultClientConfig clientServerConf := consts.DefaultClientConfig
clientVisitorConf := consts.DefaultClientConfig clientVisitorConf := consts.DefaultClientConfig
@ -381,8 +381,8 @@ var _ = Describe("[Feature: Basic]", func() {
} }
}) })
Describe("TCPMUX", func() { ginkgo.Describe("TCPMUX", func() {
It("Type tcpmux", func() { ginkgo.It("Type tcpmux", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig

View File

@ -6,18 +6,18 @@ import (
"strings" "strings"
"time" "time"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client" clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: ClientManage]", func() { var _ = ginkgo.Describe("[Feature: ClientManage]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
It("Update && Reload API", func() { ginkgo.It("Update && Reload API", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
adminPort := f.AllocPort() adminPort := f.AllocPort()
@ -62,7 +62,9 @@ var _ = Describe("[Feature: ClientManage]", func() {
// change p2 port and remove p3 proxy // change p2 port and remove p3 proxy
newClientConf := strings.ReplaceAll(conf, strconv.Itoa(p2Port), strconv.Itoa(newP2Port)) newClientConf := strings.ReplaceAll(conf, strconv.Itoa(p2Port), strconv.Itoa(newP2Port))
p3Index := strings.Index(newClientConf, "[p3]") p3Index := strings.Index(newClientConf, "[p3]")
if p3Index >= 0 {
newClientConf = newClientConf[:p3Index] newClientConf = newClientConf[:p3Index]
}
err = client.UpdateConfig(newClientConf) err = client.UpdateConfig(newClientConf)
framework.ExpectNoError(err) framework.ExpectNoError(err)
@ -77,7 +79,7 @@ var _ = Describe("[Feature: ClientManage]", func() {
framework.NewRequestExpect(f).Port(p3Port).Explain("p3 port").ExpectError(true).Ensure() framework.NewRequestExpect(f).Port(p3Port).Explain("p3 port").ExpectError(true).Ensure()
}) })
It("healthz", func() { ginkgo.It("healthz", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
dashboardPort := f.AllocPort() dashboardPort := f.AllocPort()
@ -99,5 +101,4 @@ var _ = Describe("[Feature: ClientManage]", func() {
}).Port(dashboardPort). }).Port(dashboardPort).
Ensure(framework.ExpectResponseCode(401)) Ensure(framework.ExpectResponseCode(401))
}) })
}) })

View File

@ -4,12 +4,12 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/cert" "github.com/fatedier/frp/test/e2e/pkg/cert"
"github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/port"
. "github.com/onsi/ginkgo"
) )
type generalTestConfigures struct { type generalTestConfigures struct {
@ -54,15 +54,15 @@ func runClientServerTest(f *framework.Framework, configures *generalTestConfigur
// defineClientServerTest test a normal tcp and udp proxy with specified TestConfigures. // defineClientServerTest test a normal tcp and udp proxy with specified TestConfigures.
func defineClientServerTest(desc string, f *framework.Framework, configures *generalTestConfigures) { func defineClientServerTest(desc string, f *framework.Framework, configures *generalTestConfigures) {
It(desc, func() { ginkgo.It(desc, func() {
runClientServerTest(f, configures) runClientServerTest(f, configures)
}) })
} }
var _ = Describe("[Feature: Client-Server]", func() { var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
Describe("Protocol", func() { ginkgo.Describe("Protocol", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
configures := &generalTestConfigures{ configures := &generalTestConfigures{
@ -76,7 +76,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
} }
}) })
Describe("Authentication", func() { ginkgo.Describe("Authentication", func() {
defineClientServerTest("Token Correct", f, &generalTestConfigures{ defineClientServerTest("Token Correct", f, &generalTestConfigures{
server: "token = 123456", server: "token = 123456",
client: "token = 123456", client: "token = 123456",
@ -89,7 +89,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
}) })
}) })
Describe("TLS", func() { ginkgo.Describe("TLS", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
@ -114,7 +114,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
}) })
}) })
Describe("TLS with custom certificate", func() { ginkgo.Describe("TLS with custom certificate", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "websocket"}
var ( var (
@ -122,7 +122,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
serverCrtPath, serverKeyPath string serverCrtPath, serverKeyPath string
clientCrtPath, clientKeyPath string clientCrtPath, clientKeyPath string
) )
JustBeforeEach(func() { ginkgo.JustBeforeEach(func() {
generator := &cert.SelfSignedCertGenerator{} generator := &cert.SelfSignedCertGenerator{}
artifacts, err := generator.Generate("0.0.0.0") artifacts, err := generator.Generate("0.0.0.0")
framework.ExpectNoError(err) framework.ExpectNoError(err)
@ -131,7 +131,8 @@ var _ = Describe("[Feature: Client-Server]", func() {
serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert)) serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key)) serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
generator.SetCA(artifacts.CACert, artifacts.CAKey) generator.SetCA(artifacts.CACert, artifacts.CAKey)
generator.Generate("0.0.0.0") _, err = generator.Generate("0.0.0.0")
framework.ExpectNoError(err)
clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert)) clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert))
clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key)) clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
}) })
@ -139,7 +140,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
It("one-way authentication: "+tmp, func() { ginkgo.It("one-way authentication: "+tmp, func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
protocol = %s protocol = %s
@ -155,7 +156,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
}) })
}) })
It("mutual authentication: "+tmp, func() { ginkgo.It("mutual authentication: "+tmp, func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
protocol = %s protocol = %s
@ -176,13 +177,13 @@ var _ = Describe("[Feature: Client-Server]", func() {
} }
}) })
Describe("TLS with custom certificate and specified server name", func() { ginkgo.Describe("TLS with custom certificate and specified server name", func() {
var ( var (
caCrtPath string caCrtPath string
serverCrtPath, serverKeyPath string serverCrtPath, serverKeyPath string
clientCrtPath, clientKeyPath string clientCrtPath, clientKeyPath string
) )
JustBeforeEach(func() { ginkgo.JustBeforeEach(func() {
generator := &cert.SelfSignedCertGenerator{} generator := &cert.SelfSignedCertGenerator{}
artifacts, err := generator.Generate("example.com") artifacts, err := generator.Generate("example.com")
framework.ExpectNoError(err) framework.ExpectNoError(err)
@ -191,12 +192,13 @@ var _ = Describe("[Feature: Client-Server]", func() {
serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert)) serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key)) serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
generator.SetCA(artifacts.CACert, artifacts.CAKey) generator.SetCA(artifacts.CACert, artifacts.CAKey)
generator.Generate("example.com") _, err = generator.Generate("example.com")
framework.ExpectNoError(err)
clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert)) clientCrtPath = f.WriteTempFile("client.crt", string(artifacts.Cert))
clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key)) clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
}) })
It("mutual authentication", func() { ginkgo.It("mutual authentication", func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
tls_cert_file = %s tls_cert_file = %s
@ -213,7 +215,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
}) })
}) })
It("mutual authentication with incorrect server name", func() { ginkgo.It("mutual authentication with incorrect server name", func() {
runClientServerTest(f, &generalTestConfigures{ runClientServerTest(f, &generalTestConfigures{
server: fmt.Sprintf(` server: fmt.Sprintf(`
tls_cert_file = %s tls_cert_file = %s
@ -232,7 +234,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
}) })
}) })
Describe("TLS with disable_custom_tls_first_byte", func() { ginkgo.Describe("TLS with disable_custom_tls_first_byte", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol
@ -250,7 +252,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
} }
}) })
Describe("IPv6 bind address", func() { ginkgo.Describe("IPv6 bind address", func() {
supportProtocols := []string{"tcp", "kcp", "websocket"} supportProtocols := []string{"tcp", "kcp", "websocket"}
for _, protocol := range supportProtocols { for _, protocol := range supportProtocols {
tmp := protocol tmp := protocol

View File

@ -5,21 +5,21 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
. "github.com/onsi/ginkgo"
) )
const ( const (
ConfigValidStr = "syntax is ok" ConfigValidStr = "syntax is ok"
) )
var _ = Describe("[Feature: Cmd]", func() { var _ = ginkgo.Describe("[Feature: Cmd]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
Describe("Verify", func() { ginkgo.Describe("Verify", func() {
It("frps valid", func() { ginkgo.It("frps valid", func() {
path := f.GenerateConfigFile(` path := f.GenerateConfigFile(`
[common] [common]
bind_addr = 0.0.0.0 bind_addr = 0.0.0.0
@ -29,7 +29,7 @@ var _ = Describe("[Feature: Cmd]", func() {
framework.ExpectNoError(err) framework.ExpectNoError(err)
framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output) framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output)
}) })
It("frps invalid", func() { ginkgo.It("frps invalid", func() {
path := f.GenerateConfigFile(` path := f.GenerateConfigFile(`
[common] [common]
bind_addr = 0.0.0.0 bind_addr = 0.0.0.0
@ -39,7 +39,7 @@ var _ = Describe("[Feature: Cmd]", func() {
framework.ExpectNoError(err) framework.ExpectNoError(err)
framework.ExpectTrue(!strings.Contains(output, ConfigValidStr), "output: %s", output) framework.ExpectTrue(!strings.Contains(output, ConfigValidStr), "output: %s", output)
}) })
It("frpc valid", func() { ginkgo.It("frpc valid", func() {
path := f.GenerateConfigFile(` path := f.GenerateConfigFile(`
[common] [common]
server_addr = 0.0.0.0 server_addr = 0.0.0.0
@ -49,7 +49,7 @@ var _ = Describe("[Feature: Cmd]", func() {
framework.ExpectNoError(err) framework.ExpectNoError(err)
framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output) framework.ExpectTrue(strings.Contains(output, ConfigValidStr), "output: %s", output)
}) })
It("frpc invalid", func() { ginkgo.It("frpc invalid", func() {
path := f.GenerateConfigFile(` path := f.GenerateConfigFile(`
[common] [common]
server_addr = 0.0.0.0 server_addr = 0.0.0.0
@ -62,8 +62,8 @@ var _ = Describe("[Feature: Cmd]", func() {
}) })
}) })
Describe("Single proxy", func() { ginkgo.Describe("Single proxy", func() {
It("TCP", func() { ginkgo.It("TCP", func() {
serverPort := f.AllocPort() serverPort := f.AllocPort()
_, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort)) _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort))
framework.ExpectNoError(err) framework.ExpectNoError(err)
@ -77,7 +77,7 @@ var _ = Describe("[Feature: Cmd]", func() {
framework.NewRequestExpect(f).Port(remotePort).Ensure() framework.NewRequestExpect(f).Port(remotePort).Ensure()
}) })
It("UDP", func() { ginkgo.It("UDP", func() {
serverPort := f.AllocPort() serverPort := f.AllocPort()
_, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort)) _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort))
framework.ExpectNoError(err) framework.ExpectNoError(err)
@ -92,7 +92,7 @@ var _ = Describe("[Feature: Cmd]", func() {
Port(remotePort).Ensure() Port(remotePort).Ensure()
}) })
It("HTTP", func() { ginkgo.It("HTTP", func() {
serverPort := f.AllocPort() serverPort := f.AllocPort()
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
_, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost_http_port", strconv.Itoa(vhostHTTPPort)) _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost_http_port", strconv.Itoa(vhostHTTPPort))

View File

@ -3,18 +3,18 @@ package basic
import ( import (
"fmt" "fmt"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/port"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: Config]", func() { var _ = ginkgo.Describe("[Feature: Config]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
Describe("Template", func() { ginkgo.Describe("Template", func() {
It("render by env", func() { ginkgo.It("render by env", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -39,8 +39,8 @@ var _ = Describe("[Feature: Config]", func() {
}) })
}) })
Describe("Includes", func() { ginkgo.Describe("Includes", func() {
It("split tcp proxies into different files", func() { ginkgo.It("split tcp proxies into different files", func() {
serverPort := f.AllocPort() serverPort := f.AllocPort()
serverConfigPath := f.GenerateConfigFile(fmt.Sprintf(` serverConfigPath := f.GenerateConfigFile(fmt.Sprintf(`
[common] [common]

View File

@ -6,16 +6,16 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"github.com/gorilla/websocket"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/mock/server/httpserver" "github.com/fatedier/frp/test/e2e/mock/server/httpserver"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
"github.com/gorilla/websocket"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: HTTP]", func() { var _ = ginkgo.Describe("[Feature: HTTP]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
getDefaultServerConf := func(vhostHTTPPort int) string { getDefaultServerConf := func(vhostHTTPPort int) string {
@ -31,7 +31,7 @@ var _ = Describe("[Feature: HTTP]", func() {
) )
} }
It("HTTP route by locations", func() { ginkgo.It("HTTP route by locations", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -78,7 +78,7 @@ var _ = Describe("[Feature: HTTP]", func() {
} }
}) })
It("HTTP route by HTTP user", func() { ginkgo.It("HTTP route by HTTP user", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -138,7 +138,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("HTTP Basic Auth", func() { ginkgo.It("HTTP Basic Auth", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -176,7 +176,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("Wildcard domain", func() { ginkgo.It("Wildcard domain", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -212,7 +212,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("Subdomain", func() { ginkgo.It("Subdomain", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
serverConf += ` serverConf += `
@ -257,7 +257,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("Modify headers", func() { ginkgo.It("Modify headers", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -265,7 +265,7 @@ var _ = Describe("[Feature: HTTP]", func() {
localServer := httpserver.New( localServer := httpserver.New(
httpserver.WithBindPort(localPort), httpserver.WithBindPort(localPort),
httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte(req.Header.Get("X-From-Where"))) _, _ = w.Write([]byte(req.Header.Get("X-From-Where")))
})), })),
) )
f.RunServer("", localServer) f.RunServer("", localServer)
@ -290,7 +290,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("Host Header Rewrite", func() { ginkgo.It("Host Header Rewrite", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)
@ -298,7 +298,7 @@ var _ = Describe("[Feature: HTTP]", func() {
localServer := httpserver.New( localServer := httpserver.New(
httpserver.WithBindPort(localPort), httpserver.WithBindPort(localPort),
httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { httpserver.WithHandler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte(req.Host)) _, _ = w.Write([]byte(req.Host))
})), })),
) )
f.RunServer("", localServer) f.RunServer("", localServer)
@ -322,7 +322,7 @@ var _ = Describe("[Feature: HTTP]", func() {
Ensure() Ensure()
}) })
It("Websocket protocol", func() { ginkgo.It("Websocket protocol", func() {
vhostHTTPPort := f.AllocPort() vhostHTTPPort := f.AllocPort()
serverConf := getDefaultServerConf(vhostHTTPPort) serverConf := getDefaultServerConf(vhostHTTPPort)

View File

@ -5,19 +5,19 @@ import (
"net" "net"
"strconv" "strconv"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/port" "github.com/fatedier/frp/test/e2e/pkg/port"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client" clientsdk "github.com/fatedier/frp/test/e2e/pkg/sdk/client"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: Server Manager]", func() { var _ = ginkgo.Describe("[Feature: Server Manager]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
It("Ports Whitelist", func() { ginkgo.It("Ports Whitelist", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -80,7 +80,7 @@ var _ = Describe("[Feature: Server Manager]", func() {
}).ExpectError(true).Ensure() }).ExpectError(true).Ensure()
}) })
It("Alloc Random Port", func() { ginkgo.It("Alloc Random Port", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -124,7 +124,7 @@ var _ = Describe("[Feature: Server Manager]", func() {
framework.NewRequestExpect(f).Protocol("udp").Port(port).Ensure() framework.NewRequestExpect(f).Protocol("udp").Port(port).Ensure()
}) })
It("Port Reuse", func() { ginkgo.It("Port Reuse", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
// Use same port as PortServer // Use same port as PortServer
serverConf += fmt.Sprintf(` serverConf += fmt.Sprintf(`
@ -145,7 +145,7 @@ var _ = Describe("[Feature: Server Manager]", func() {
}).PortName(consts.PortServerName).Ensure() }).PortName(consts.PortServerName).Ensure()
}) })
It("healthz", func() { ginkgo.It("healthz", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
dashboardPort := f.AllocPort() dashboardPort := f.AllocPort()

View File

@ -3,12 +3,12 @@ package e2e
import ( import (
"testing" "testing"
"github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/onsi/ginkgo" "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config" "github.com/onsi/ginkgo/config"
"github.com/onsi/gomega" "github.com/onsi/gomega"
"github.com/fatedier/frp/pkg/util/log"
"github.com/fatedier/frp/test/e2e/framework"
) )
var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {

View File

@ -6,15 +6,14 @@ import (
"os" "os"
"testing" "testing"
"github.com/fatedier/frp/pkg/util/log" _ "github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/pkg/util/log"
// test source // test source
_ "github.com/fatedier/frp/test/e2e/basic" _ "github.com/fatedier/frp/test/e2e/basic"
_ "github.com/fatedier/frp/test/e2e/features" _ "github.com/fatedier/frp/test/e2e/features"
"github.com/fatedier/frp/test/e2e/framework"
_ "github.com/fatedier/frp/test/e2e/plugin" _ "github.com/fatedier/frp/test/e2e/plugin"
_ "github.com/onsi/ginkgo"
) )
// handleFlags sets up all flags and parses the command line. // handleFlags sets up all flags and parses the command line.

View File

@ -3,17 +3,17 @@ package e2e
import ( import (
"fmt" "fmt"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: Example]", func() { var _ = ginkgo.Describe("[Feature: Example]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
Describe("TCP", func() { ginkgo.Describe("TCP", func() {
It("Expose a TCP echo server", func() { ginkgo.It("Expose a TCP echo server", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig

View File

@ -5,18 +5,18 @@ import (
"strings" "strings"
"time" "time"
"github.com/onsi/ginkgo"
"github.com/fatedier/frp/test/e2e/framework" "github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts" "github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/mock/server/streamserver" "github.com/fatedier/frp/test/e2e/mock/server/streamserver"
"github.com/fatedier/frp/test/e2e/pkg/request" "github.com/fatedier/frp/test/e2e/pkg/request"
. "github.com/onsi/ginkgo"
) )
var _ = Describe("[Feature: Bandwidth Limit]", func() { var _ = ginkgo.Describe("[Feature: Bandwidth Limit]", func() {
f := framework.NewDefaultFramework() f := framework.NewDefaultFramework()
It("Proxy Bandwidth Limit", func() { ginkgo.It("Proxy Bandwidth Limit", func() {
serverConf := consts.DefaultServerConfig serverConf := consts.DefaultServerConfig
clientConf := consts.DefaultClientConfig clientConf := consts.DefaultClientConfig
@ -40,7 +40,7 @@ var _ = Describe("[Feature: Bandwidth Limit]", func() {
framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) { framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) {
r.Body([]byte(content)).Timeout(30 * time.Second) r.Body([]byte(content)).Timeout(30 * time.Second)
}).ExpectResp([]byte(content)).Ensure() }).ExpectResp([]byte(content)).Ensure()
duration := time.Now().Sub(start) duration := time.Since(start)
framework.ExpectTrue(duration.Seconds() > 7, "100Kb with 10KB limit, want > 7 seconds, but got %d seconds", duration.Seconds()) framework.ExpectTrue(duration.Seconds() > 7, "100Kb with 10KB limit, want > 7 seconds, but got %d seconds", duration.Seconds())
}) })

Some files were not shown because too many files have changed in this diff Show More