Browse Source

lint by golangci-lint (#3080)

fatedier 2 years ago
parent
commit
9d077b02cf
100 changed files with 816 additions and 1212 deletions
  1. 4 2
      .circleci/config.yml
  2. 41 0
      .github/workflows/golangci-lint.yml
  3. 1 1
      .github/workflows/goreleaser.yml
  4. 141 0
      .golangci.yml
  5. 5 3
      client/admin.go
  6. 5 7
      client/admin_api.go
  7. 19 26
      client/control.go
  8. 1 3
      client/event/event.go
  9. 5 7
      client/health/health.go
  10. 40 28
      client/proxy/proxy.go
  11. 4 6
      client/proxy/proxy_manager.go
  12. 9 9
      client/proxy/proxy_wrapper.go
  13. 13 9
      client/service.go
  14. 21 20
      client/visitor.go
  15. 4 7
      client/visitor_manager.go
  16. 2 2
      cmd/frpc/sub/http.go
  17. 2 2
      cmd/frpc/sub/reload.go
  18. 4 5
      cmd/frpc/sub/root.go
  19. 3 3
      cmd/frpc/sub/status.go
  20. 2 2
      cmd/frpc/sub/stcp.go
  21. 2 2
      cmd/frpc/sub/sudp.go
  22. 2 2
      cmd/frpc/sub/udp.go
  23. 2 2
      cmd/frpc/sub/verify.go
  24. 2 2
      cmd/frpc/sub/xtcp.go
  25. 4 7
      cmd/frps/root.go
  26. 2 2
      cmd/frps/verify.go
  27. 1 1
      dockerfiles/Dockerfile-for-frpc
  28. 1 1
      dockerfiles/Dockerfile-for-frps
  29. 38 5
      go.mod
  30. 0 2
      go.sum
  31. 1 1
      hack/run-e2e.sh
  32. 3 3
      pkg/auth/oidc.go
  33. 11 9
      pkg/config/client.go
  34. 3 5
      pkg/config/client_test.go
  35. 1 1
      pkg/config/parse.go
  36. 2 6
      pkg/config/proxy.go
  37. 2 4
      pkg/config/proxy_test.go
  38. 4 5
      pkg/config/server.go
  39. 6 6
      pkg/config/server_test.go
  40. 4 3
      pkg/config/types.go
  41. 1 3
      pkg/config/value.go
  42. 3 2
      pkg/config/visitor.go
  43. 2 2
      pkg/config/visitor_test.go
  44. 16 16
      pkg/consts/consts.go
  45. 1 1
      pkg/metrics/aggregate/server.go
  46. 6 3
      pkg/metrics/mem/server.go
  47. 4 2
      pkg/metrics/metrics.go
  48. 2 2
      pkg/metrics/prometheus/server.go
  49. 1 3
      pkg/msg/ctl.go
  50. 22 26
      pkg/msg/msg.go
  51. 9 9
      pkg/nathole/nathole.go
  52. 6 3
      pkg/plugin/client/http2https.go
  53. 13 9
      pkg/plugin/client/http_proxy.go
  54. 4 2
      pkg/plugin/client/https2http.go
  55. 4 2
      pkg/plugin/client/https2https.go
  56. 3 6
      pkg/plugin/client/socks5.go
  57. 6 4
      pkg/plugin/client/static_file.go
  58. 3 1
      pkg/plugin/client/unix_domain_socket.go
  59. 2 2
      pkg/plugin/server/http.go
  60. 1 2
      pkg/plugin/server/manager.go
  61. 5 7
      pkg/proto/udp/udp.go
  62. 3 3
      pkg/transport/tls.go
  63. 5 5
      pkg/util/log/log.go
  64. 2 2
      pkg/util/net/kcp.go
  65. 7 9
      pkg/util/net/tls.go
  66. 4 5
      pkg/util/net/udp.go
  67. 5 6
      pkg/util/net/websocket.go
  68. 13 4
      pkg/util/tcpmux/httpconnect.go
  69. 2 4
      pkg/util/util/http.go
  70. 5 4
      pkg/util/util/util.go
  71. 1 1
      pkg/util/version/version.go
  72. 27 11
      pkg/util/vhost/http.go
  73. 1 3
      pkg/util/vhost/resource.go
  74. 0 636
      pkg/util/vhost/reverseproxy.go
  75. 3 3
      pkg/util/vhost/router.go
  76. 24 18
      pkg/util/vhost/vhost.go
  77. 12 13
      server/control.go
  78. 6 4
      server/dashboard.go
  79. 7 7
      server/dashboard_api.go
  80. 1 3
      server/group/http.go
  81. 4 5
      server/group/tcp.go
  82. 2 5
      server/group/tcpmux.go
  83. 3 3
      server/proxy/http.go
  84. 1 1
      server/proxy/https.go
  85. 4 4
      server/proxy/proxy.go
  86. 9 7
      server/proxy/udp.go
  87. 3 3
      server/proxy/xtcp.go
  88. 28 24
      server/service.go
  89. 4 4
      server/visitor/visitor.go
  90. 14 14
      test/e2e/basic/basic.go
  91. 8 7
      test/e2e/basic/client.go
  92. 21 19
      test/e2e/basic/client_server.go
  93. 12 12
      test/e2e/basic/cmd.go
  94. 7 7
      test/e2e/basic/config.go
  95. 14 14
      test/e2e/basic/http.go
  96. 7 7
      test/e2e/basic/server.go
  97. 3 3
      test/e2e/e2e.go
  98. 3 4
      test/e2e/e2e_test.go
  99. 5 5
      test/e2e/examples.go
  100. 5 5
      test/e2e/features/bandwidth_limit.go

+ 4 - 2
.circleci/config.yml

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

+ 41 - 0
.github/workflows/golangci-lint.yml

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

+ 1 - 1
.github/workflows/goreleaser.yml

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

+ 141 - 0
.golangci.yml

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

+ 5 - 3
client/admin.go

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

+ 5 - 7
client/admin_api.go

@@ -49,7 +49,7 @@ func (svr *Service) apiReload(w http.ResponseWriter, r *http.Request) {
 		log.Info("api response [/api/reload], code [%d]", res.Code)
 		w.WriteHeader(res.Code)
 		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
 	}
 	log.Info("success reload conf")
-	return
 }
 
 type StatusResp struct {
@@ -173,7 +172,7 @@ func (svr *Service) apiStatus(w http.ResponseWriter, r *http.Request) {
 	defer func() {
 		log.Info("Http response [/api/status]")
 		buf, _ = json.Marshal(&res)
-		w.Write(buf)
+		_, _ = w.Write(buf)
 	}()
 
 	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.XTCP))
 	sort.Sort(ByProxyStatusResp(res.SUDP))
-	return
 }
 
 // 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)
 		w.WriteHeader(res.Code)
 		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)
 		w.WriteHeader(res.Code)
 		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")
 
-	err = os.WriteFile(svr.cfgFile, []byte(content), 0644)
+	err = os.WriteFile(svr.cfgFile, []byte(content), 0o644)
 	if err != nil {
 		res.Code = 500
 		res.Msg = fmt.Sprintf("write content to frpc config file error: %v", err)

+ 19 - 26
client/control.go

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

+ 1 - 3
client/event/event.go

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

+ 5 - 7
client/health/health.go

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

+ 40 - 28
client/proxy/proxy.go

@@ -24,14 +24,6 @@ import (
 	"sync"
 	"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"
 	frpIo "github.com/fatedier/golib/io"
 	libdial "github.com/fatedier/golib/net/dial"
@@ -39,6 +31,14 @@ import (
 	fmux "github.com/hashicorp/yamux"
 	pp "github.com/pires/go-proxyproto"
 	"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.
@@ -322,7 +322,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
 
 	// Wait for client address at most 5 seconds.
 	var natHoleRespMsg msg.NatHoleResp
-	clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
+	_ = clientConn.SetReadDeadline(time.Now().Add(5 * time.Second))
 
 	buf := pool.GetBuf(1024)
 	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)
 		return
 	}
-	clientConn.SetReadDeadline(time.Time{})
-	clientConn.Close()
+	_ = clientConn.SetReadDeadline(time.Time{})
+	_ = clientConn.Close()
 
 	if 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)
 		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")
 
-	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
 	lConn, err := net.ListenUDP("udp", laddr)
@@ -370,7 +373,7 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
 	}
 	defer lConn.Close()
 
-	lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
+	_ = lConn.SetReadDeadline(time.Now().Add(8 * time.Second))
 	sidBuf := pool.GetBuf(1024)
 	var uAddr *net.UDPAddr
 	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)
 		return
 	}
-	lConn.SetReadDeadline(time.Time{})
+	_ = lConn.SetReadDeadline(time.Time{})
 	if string(sidBuf[:n]) != natHoleRespMsg.Sid {
 		xl.Warn("incorrect sid from visitor")
 		return
@@ -386,7 +389,10 @@ func (pxy *XTCPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
 	pool.PutBuf(sidBuf)
 	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())
 	if err != nil {
@@ -424,12 +430,13 @@ func (pxy *XTCPProxy) sendDetectMsg(addr string, port int, laddr *net.UDPAddr, c
 		return err
 	}
 
-	//uConn := ipv4.NewConn(tConn)
-	//uConn.SetTTL(3)
+	// uConn := ipv4.NewConn(tConn)
+	// uConn.SetTTL(3)
 
-	tConn.Write(content)
-	tConn.Close()
-	return nil
+	if _, err := tConn.Write(content); err != nil {
+		return err
+	}
+	return tConn.Close()
 }
 
 // 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
 		for {
 			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 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))
 }
 
@@ -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)
 		defer func() {
 			ticker.Stop()
@@ -711,14 +718,15 @@ func (pxy *SUDPProxy) InWorkConn(conn net.Conn, m *msg.StartWorkConn) {
 
 	go workConnSenderFn(workConn, sendCh)
 	go workConnReaderFn(workConn, readCh)
-	go heartbeatFn(workConn, sendCh)
+	go heartbeatFn(sendCh)
 
 	udp.Forwarder(pxy.localAddr, readCh, sendCh, int(pxy.clientCfg.UDPPacketSize))
 }
 
 // Common handler for tcp work connections.
 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)
 	var (
 		remote io.ReadWriteCloser
@@ -773,7 +781,7 @@ func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf
 			}
 
 			buf := bytes.NewBuffer(nil)
-			h.WriteTo(buf)
+			_, _ = h.WriteTo(buf)
 			extraInfo = buf.Bytes()
 		}
 	}
@@ -800,7 +808,11 @@ func HandleTCPWorkConnection(ctx context.Context, localInfo *config.LocalSvrConf
 		localConn.RemoteAddr().String(), workConn.LocalAddr().String(), workConn.RemoteAddr().String())
 
 	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)

+ 4 - 6
client/proxy/proxy_manager.go

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

+ 9 - 9
client/proxy/proxy_wrapper.go

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

+ 13 - 9
client/service.go

@@ -28,6 +28,10 @@ import (
 	"sync/atomic"
 	"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/pkg/auth"
 	"github.com/fatedier/frp/pkg/config"
@@ -38,10 +42,6 @@ import (
 	"github.com/fatedier/frp/pkg/util/util"
 	"github.com/fatedier/frp/pkg/util/version"
 	"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() {
@@ -81,8 +81,12 @@ type Service struct {
 	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())
 	svr = &Service{
 		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)
 				util.RandomSleep(delayTime, 0.9, 1.1)
 
-				delayTime = delayTime * 2
+				delayTime *= 2
 				if delayTime > maxDelayTime {
 					delayTime = maxDelayTime
 				}
@@ -333,11 +337,11 @@ func (svr *Service) login() (conn net.Conn, session *fmux.Session, err error) {
 	}
 
 	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 {
 		return
 	}
-	conn.SetReadDeadline(time.Time{})
+	_ = conn.SetReadDeadline(time.Time{})
 
 	if loginRespMsg.Error != "" {
 		err = fmt.Errorf("%s", loginRespMsg.Error)

+ 21 - 20
client/visitor.go

@@ -24,17 +24,17 @@ import (
 	"sync"
 	"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/msg"
 	"github.com/fatedier/frp/pkg/proto/udp"
 	frpNet "github.com/fatedier/frp/pkg/util/net"
 	"github.com/fatedier/frp/pkg/util/util"
 	"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.
@@ -71,9 +71,8 @@ func NewVisitor(ctx context.Context, ctl *Control, cfg config.VisitorConf) (visi
 }
 
 type BaseVisitor struct {
-	ctl    *Control
-	l      net.Listener
-	closed bool
+	ctl *Control
+	l   net.Listener
 
 	mu  sync.RWMutex
 	ctx context.Context
@@ -138,13 +137,13 @@ func (sv *STCPVisitor) handleConn(userConn net.Conn) {
 	}
 
 	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)
 	if err != nil {
 		xl.Warn("get newVisitorConnRespMsg error: %v", err)
 		return
 	}
-	visitorConn.SetReadDeadline(time.Time{})
+	_ = visitorConn.SetReadDeadline(time.Time{})
 
 	if 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.
 	var natHoleRespMsg msg.NatHoleResp
-	visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
+	_ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
 	buf := pool.GetBuf(1024)
 	n, err := visitorConn.Read(buf)
 	if err != nil {
@@ -252,7 +251,7 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
 		xl.Warn("get natHoleRespMsg error: %v", err)
 		return
 	}
-	visitorConn.SetReadDeadline(time.Time{})
+	_ = visitorConn.SetReadDeadline(time.Time{})
 	pool.PutBuf(buf)
 
 	if natHoleRespMsg.Error != "" {
@@ -279,17 +278,20 @@ func (sv *XTCPVisitor) handleConn(userConn net.Conn) {
 	}
 	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
 	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)
 	if err != nil {
 		xl.Warn("get sid from client error: %v", err)
 		return
 	}
-	lConn.SetReadDeadline(time.Time{})
+	_ = lConn.SetReadDeadline(time.Time{})
 	if string(sidBuf[:n]) != natHoleRespMsg.Sid {
 		xl.Warn("incorrect sid from client")
 		return
@@ -411,7 +413,6 @@ func (sv *SUDPVisitor) dispatcher() {
 		default:
 		}
 	}
-
 }
 
 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
-			conn.SetReadDeadline(time.Now().Add(60 * time.Second))
+			_ = conn.SetReadDeadline(time.Now().Add(60 * time.Second))
 			if rawMsg, errRet = msg.ReadMsg(conn); errRet != nil {
 				xl.Warn("read from workconn for user udp conn error: %v", errRet)
 				return
 			}
 
-			conn.SetReadDeadline(time.Time{})
+			_ = conn.SetReadDeadline(time.Time{})
 			switch m := rawMsg.(type) {
 			case *msg.Ping:
 				xl.Debug("frpc visitor get ping message from frpc")
@@ -523,12 +524,12 @@ func (sv *SUDPVisitor) getNewVisitorConn() (net.Conn, error) {
 	}
 
 	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)
 	if err != nil {
 		return nil, fmt.Errorf("frpc read newVisitorConnRespMsg error: %v", err)
 	}
-	visitorConn.SetReadDeadline(time.Time{})
+	_ = visitorConn.SetReadDeadline(time.Time{})
 
 	if newVisitorConnRespMsg.Error != "" {
 		return nil, fmt.Errorf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)

+ 4 - 7
client/visitor_manager.go

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

+ 2 - 2
cmd/frpc/sub/http.go

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

+ 2 - 2
cmd/frpc/sub/reload.go

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

+ 4 - 5
cmd/frpc/sub/root.go

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

+ 3 - 3
cmd/frpc/sub/status.go

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

+ 2 - 2
cmd/frpc/sub/stcp.go

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

+ 2 - 2
cmd/frpc/sub/sudp.go

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

+ 2 - 2
cmd/frpc/sub/udp.go

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

+ 2 - 2
cmd/frpc/sub/verify.go

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

+ 2 - 2
cmd/frpc/sub/xtcp.go

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

+ 4 - 7
cmd/frps/root.go

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

+ 2 - 2
cmd/frps/verify.go

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

+ 1 - 1
dockerfiles/Dockerfile-for-frpc

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

+ 1 - 1
dockerfiles/Dockerfile-for-frps

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

+ 38 - 5
go.mod

@@ -1,6 +1,6 @@
 module github.com/fatedier/frp
 
-go 1.16
+go 1.18
 
 require (
 	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/websocket v1.4.2
 	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/gomega v1.13.0
 	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/rodaine/table v1.0.1
 	github.com/spf13/cobra v1.1.3
 	github.com/stretchr/testify v1.7.0
 	golang.org/x/net v0.0.0-20210428140749-89ef3d95e781
 	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
 	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/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
+)

+ 0 - 2
go.sum

@@ -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/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/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 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/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/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/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
 github.com/yuin/goldmark v1.1.27/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=

+ 1 - 1
hack/run-e2e.sh

@@ -5,7 +5,7 @@ ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd)
 which ginkgo &> /dev/null
 if [ $? -ne 0 ]; then
     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
 
 debug=false

+ 3 - 3
pkg/auth/oidc.go

@@ -18,10 +18,10 @@ import (
 	"context"
 	"fmt"
 
-	"github.com/fatedier/frp/pkg/msg"
-
 	"github.com/coreos/go-oidc"
 	"golang.org/x/oauth2/clientcredentials"
+
+	"github.com/fatedier/frp/pkg/msg"
 )
 
 type OidcClientConfig struct {
@@ -34,7 +34,7 @@ type OidcClientConfig struct {
 	// is "".
 	OidcClientSecret string `ini:"oidc_client_secret" json:"oidc_client_secret"`
 	// OidcAudience specifies the audience of the token in OIDC authentication
-	//if AuthenticationMethod == "oidc". By default, this value is "".
+	// if AuthenticationMethod == "oidc". By default, this value is "".
 	OidcAudience string `ini:"oidc_audience" json:"oidc_audience"`
 	// OidcTokenEndpointURL specifies the URL which implements OIDC Token Endpoint.
 	// It will be used to get an OIDC token if AuthenticationMethod == "oidc".

+ 11 - 9
pkg/config/client.go

@@ -20,10 +20,10 @@ import (
 	"path/filepath"
 	"strings"
 
+	"gopkg.in/ini.v1"
+
 	"github.com/fatedier/frp/pkg/auth"
 	"github.com/fatedier/frp/pkg/util/util"
-
-	"gopkg.in/ini.v1"
 )
 
 // ClientCommonConf contains information for a client service. It is
@@ -113,7 +113,7 @@ type ClientCommonConf struct {
 	// all supplied proxies are enabled. By default, this value is an empty
 	// set.
 	Start []string `ini:"start" json:"start"`
-	//Start map[string]struct{} `json:"start"`
+	// Start map[string]struct{} `json:"start"`
 	// Protocol specifies the protocol to use when interacting with the server.
 	// Valid values are "tcp", "kcp" and "websocket". By default, this value
 	// is "tcp".
@@ -214,7 +214,7 @@ func (cfg *ClientCommonConf) Validate() error {
 		}
 	}
 
-	if cfg.TLSEnable == false {
+	if !cfg.TLSEnable {
 		if cfg.TLSCertFile != "" {
 			fmt.Println("WARNING! tls_cert_file is invalid when tls_enable is false")
 		}
@@ -281,7 +281,6 @@ func LoadAllProxyConfsFromIni(
 	source interface{},
 	start []string,
 ) (map[string]ProxyConf, map[string]VisitorConf, error) {
-
 	f, err := ini.LoadSources(ini.LoadOptions{
 		Insensitive:         false,
 		InsensitiveSections: false,
@@ -366,7 +365,6 @@ func LoadAllProxyConfsFromIni(
 }
 
 func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
-
 	// Validation
 	localPortStr := section.Key("local_port").String()
 	remotePortStr := section.Key("remote_port").String()
@@ -404,8 +402,12 @@ func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
 		}
 
 		copySection(section, tmpsection)
-		tmpsection.NewKey("local_port", fmt.Sprintf("%d", localPorts[i]))
-		tmpsection.NewKey("remote_port", fmt.Sprintf("%d", remotePorts[i]))
+		if _, err := tmpsection.NewKey("local_port", fmt.Sprintf("%d", localPorts[i])); err != nil {
+			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
@@ -413,6 +415,6 @@ func renderRangeProxyTemplates(f *ini.File, section *ini.Section) error {
 
 func copySection(source, target *ini.Section) {
 	for key, value := range source.KeysHash() {
-		target.NewKey(key, value)
+		_, _ = target.NewKey(key, value)
 	}
 }

+ 3 - 5
pkg/config/client_test.go

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

+ 1 - 1
pkg/config/parse.go

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

+ 2 - 6
pkg/config/proxy.go

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

+ 2 - 4
pkg/config/proxy_test.go

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

+ 4 - 5
pkg/config/server.go

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

+ 6 - 6
pkg/config/server_test.go

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

+ 4 - 3
pkg/config/types.go

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

+ 1 - 3
pkg/config/value.go

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

+ 3 - 2
pkg/config/visitor.go

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

+ 2 - 2
pkg/config/visitor_test.go

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

+ 16 - 16
pkg/consts/consts.go

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

+ 1 - 1
pkg/metrics/aggregate/server.go

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

+ 6 - 3
pkg/metrics/mem/server.go

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

+ 4 - 2
pkg/metrics/metrics.go

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

+ 2 - 2
pkg/metrics/prometheus/server.go

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

+ 1 - 3
pkg/msg/ctl.go

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

+ 22 - 26
pkg/msg/msg.go

@@ -37,28 +37,26 @@ const (
 	TypeNatHoleSid            = '5'
 )
 
-var (
-	msgTypeMap = map[byte]interface{}{
-		TypeLogin:                 Login{},
-		TypeLoginResp:             LoginResp{},
-		TypeNewProxy:              NewProxy{},
-		TypeNewProxyResp:          NewProxyResp{},
-		TypeCloseProxy:            CloseProxy{},
-		TypeNewWorkConn:           NewWorkConn{},
-		TypeReqWorkConn:           ReqWorkConn{},
-		TypeStartWorkConn:         StartWorkConn{},
-		TypeNewVisitorConn:        NewVisitorConn{},
-		TypeNewVisitorConnResp:    NewVisitorConnResp{},
-		TypePing:                  Ping{},
-		TypePong:                  Pong{},
-		TypeUDPPacket:             UDPPacket{},
-		TypeNatHoleVisitor:        NatHoleVisitor{},
-		TypeNatHoleClient:         NatHoleClient{},
-		TypeNatHoleResp:           NatHoleResp{},
-		TypeNatHoleClientDetectOK: NatHoleClientDetectOK{},
-		TypeNatHoleSid:            NatHoleSid{},
-	}
-)
+var msgTypeMap = map[byte]interface{}{
+	TypeLogin:                 Login{},
+	TypeLoginResp:             LoginResp{},
+	TypeNewProxy:              NewProxy{},
+	TypeNewProxyResp:          NewProxyResp{},
+	TypeCloseProxy:            CloseProxy{},
+	TypeNewWorkConn:           NewWorkConn{},
+	TypeReqWorkConn:           ReqWorkConn{},
+	TypeStartWorkConn:         StartWorkConn{},
+	TypeNewVisitorConn:        NewVisitorConn{},
+	TypeNewVisitorConnResp:    NewVisitorConnResp{},
+	TypePing:                  Ping{},
+	TypePong:                  Pong{},
+	TypeUDPPacket:             UDPPacket{},
+	TypeNatHoleVisitor:        NatHoleVisitor{},
+	TypeNatHoleClient:         NatHoleClient{},
+	TypeNatHoleResp:           NatHoleResp{},
+	TypeNatHoleClientDetectOK: NatHoleClientDetectOK{},
+	TypeNatHoleSid:            NatHoleSid{},
+}
 
 // When frpc start, client send this message to login to server.
 type Login struct {
@@ -129,8 +127,7 @@ type NewWorkConn struct {
 	Timestamp    int64  `json:"timestamp,omitempty"`
 }
 
-type ReqWorkConn struct {
-}
+type ReqWorkConn struct{}
 
 type StartWorkConn struct {
 	ProxyName string `json:"proxy_name,omitempty"`
@@ -187,8 +184,7 @@ type NatHoleResp struct {
 	Error       string `json:"error,omitempty"`
 }
 
-type NatHoleClientDetectOK struct {
-}
+type NatHoleClientDetectOK struct{}
 
 type NatHoleSid struct {
 	Sid string `json:"sid,omitempty"`

+ 9 - 9
pkg/nathole/nathole.go

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

+ 6 - 3
pkg/plugin/client/http2https.go

@@ -86,17 +86,20 @@ func NewHTTP2HTTPSPlugin(params map[string]string) (Plugin, error) {
 	}
 
 	p.s = &http.Server{
-		Handler: rp,
+		Handler:           rp,
+		ReadHeaderTimeout: 0,
 	}
 
-	go p.s.Serve(listener)
+	go func() {
+		_ = p.s.Serve(listener)
+	}()
 
 	return p, nil
 }
 
 func (p *HTTP2HTTPSPlugin) Handle(conn io.ReadWriteCloser, realConn net.Conn, extraBufToLocal []byte) {
 	wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
-	p.l.PutConn(wrapConn)
+	_ = p.l.PutConn(wrapConn)
 }
 
 func (p *HTTP2HTTPSPlugin) Name() string {

+ 13 - 9
pkg/plugin/client/http_proxy.go

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

+ 4 - 2
pkg/plugin/client/https2http.go

@@ -106,7 +106,9 @@ func NewHTTPS2HTTPPlugin(params map[string]string) (Plugin, error) {
 	}
 	ln := tls.NewListener(listener, tlsConfig)
 
-	go p.s.Serve(ln)
+	go func() {
+		_ = p.s.Serve(ln)
+	}()
 	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) {
 	wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
-	p.l.PutConn(wrapConn)
+	_ = p.l.PutConn(wrapConn)
 }
 
 func (p *HTTPS2HTTPPlugin) Name() string {

+ 4 - 2
pkg/plugin/client/https2https.go

@@ -111,7 +111,9 @@ func NewHTTPS2HTTPSPlugin(params map[string]string) (Plugin, error) {
 	}
 	ln := tls.NewListener(listener, tlsConfig)
 
-	go p.s.Serve(ln)
+	go func() {
+		_ = p.s.Serve(ln)
+	}()
 	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) {
 	wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
-	p.l.PutConn(wrapConn)
+	_ = p.l.PutConn(wrapConn)
 }
 
 func (p *HTTPS2HTTPSPlugin) Name() string {

+ 3 - 6
pkg/plugin/client/socks5.go

@@ -19,9 +19,9 @@ import (
 	"log"
 	"net"
 
-	frpNet "github.com/fatedier/frp/pkg/util/net"
-
 	gosocks5 "github.com/armon/go-socks5"
+
+	frpNet "github.com/fatedier/frp/pkg/util/net"
 )
 
 const PluginSocks5 = "socks5"
@@ -32,9 +32,6 @@ func init() {
 
 type Socks5Plugin struct {
 	Server *gosocks5.Server
-
-	user   string
-	passwd string
 }
 
 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) {
 	defer conn.Close()
 	wrapConn := frpNet.WrapReadWriteCloserToConn(conn, realConn)
-	sp.Server.ServeConn(wrapConn)
+	_ = sp.Server.ServeConn(wrapConn)
 }
 
 func (sp *Socks5Plugin) Name() string {

+ 6 - 4
pkg/plugin/client/static_file.go

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

+ 3 - 1
pkg/plugin/client/unix_domain_socket.go

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

+ 2 - 2
pkg/plugin/server/http.go

@@ -43,12 +43,12 @@ type httpPlugin struct {
 }
 
 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
 	if strings.HasPrefix(url, "https://") {
 		tr := &http.Transport{
-			TLSClientConfig: &tls.Config{InsecureSkipVerify: options.TLSVerify == false},
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: !options.TLSVerify},
 		}
 		client = &http.Client{Transport: tr}
 	} else {

+ 1 - 2
pkg/plugin/server/manager.go

@@ -154,9 +154,8 @@ func (m *Manager) CloseProxy(content *CloseProxyContent) error {
 
 	if len(errs) > 0 {
 		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) {

+ 5 - 7
pkg/proto/udp/udp.go

@@ -20,10 +20,10 @@ import (
 	"sync"
 	"time"
 
-	"github.com/fatedier/frp/pkg/msg"
-
 	"github.com/fatedier/golib/errors"
 	"github.com/fatedier/golib/pool"
+
+	"github.com/fatedier/frp/pkg/msg"
 )
 
 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 {
 				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) {
-	var (
-		mu sync.RWMutex
-	)
+	var mu sync.RWMutex
 	udpConnMap := make(map[string]*net.UDPConn)
 
 	// 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)
 		for {
-			udpConn.SetReadDeadline(time.Now().Add(30 * time.Second))
+			_ = udpConn.SetReadDeadline(time.Now().Add(30 * time.Second))
 			n, _, err := udpConn.ReadFromUDP(buf)
 			if err != nil {
 				return

+ 3 - 3
pkg/transport/tls.go

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

+ 5 - 5
pkg/util/log/log.go

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

+ 2 - 2
pkg/util/net/kcp.go

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

+ 7 - 9
pkg/util/net/tls.go

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

+ 4 - 5
pkg/util/net/udp.go

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

+ 5 - 6
pkg/util/net/websocket.go

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

+ 13 - 4
pkg/util/tcpmux/httpconnect.go

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

+ 2 - 4
pkg/util/util/http.go

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

+ 5 - 4
pkg/util/util/util.go

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

+ 1 - 1
pkg/util/version/version.go

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

+ 27 - 11
pkg/util/vhost/http.go

@@ -23,27 +23,26 @@ import (
 	"log"
 	"net"
 	"net/http"
+	"net/http/httputil"
 	"net/url"
 	"strings"
 	"time"
 
-	frpLog "github.com/fatedier/frp/pkg/util/log"
-	"github.com/fatedier/frp/pkg/util/util"
 	frpIo "github.com/fatedier/golib/io"
-
 	"github.com/fatedier/golib/pool"
-)
 
-var (
-	ErrNoRouteFound = errors.New("no route found")
+	frpLog "github.com/fatedier/frp/pkg/util/log"
+	"github.com/fatedier/frp/pkg/util/util"
 )
 
+var ErrNoRouteFound = errors.New("no route found")
+
 type HTTPReverseProxyOptions struct {
 	ResponseHeaderTimeoutS int64
 }
 
 type HTTPReverseProxy struct {
-	proxy       *ReverseProxy
+	proxy       *httputil.ReverseProxy
 	vhostRouter *Routers
 
 	responseHeaderTimeout time.Duration
@@ -57,7 +56,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 		responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
 		vhostRouter:           vhostRouter,
 	}
-	proxy := &ReverseProxy{
+	proxy := &httputil.ReverseProxy{
 		// Modify incoming requests by route policies.
 		Director: func(req *http.Request) {
 			req.URL.Scheme = "http"
@@ -81,7 +80,6 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 			} else {
 				req.URL.Host = req.Host
 			}
-
 		},
 		// Create a connection to one proxy routed by route policy.
 		Transport: &http.Transport{
@@ -114,7 +112,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 		ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
 			frpLog.Warn("do http proxy request [host: %s] error: %v", req.Host, err)
 			rw.WriteHeader(http.StatusNotFound)
-			rw.Write(getNotFoundPageContent())
+			_, _ = rw.Write(getNotFoundPageContent())
 		},
 	}
 	rp.proxy = proxy
@@ -257,10 +255,28 @@ func (rp *HTTPReverseProxy) connectHandler(rw http.ResponseWriter, req *http.Req
 		client.Close()
 		return
 	}
-	req.Write(remote)
+	_ = req.Write(remote)
 	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 {
 	newctx := req.Context()
 	newctx = context.WithValue(newctx, RouteInfoURL, req.URL.Path)

+ 1 - 3
pkg/util/vhost/resource.go

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

+ 0 - 636
pkg/util/vhost/reverseproxy.go

@@ -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
-}

+ 3 - 3
pkg/util/vhost/router.go

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

+ 24 - 18
pkg/util/vhost/vhost.go

@@ -19,11 +19,11 @@ import (
 	"strings"
 	"time"
 
+	"github.com/fatedier/golib/errors"
+
 	"github.com/fatedier/frp/pkg/util/log"
 	frpNet "github.com/fatedier/frp/pkg/util/net"
 	"github.com/fatedier/frp/pkg/util/xlog"
-
-	"github.com/fatedier/golib/errors"
 )
 
 type RouteInfo string
@@ -36,10 +36,12 @@ const (
 	RouteInfoURLHost  RouteInfo = "urlHost"
 )
 
-type muxFunc func(net.Conn) (net.Conn, map[string]string, error)
-type httpAuthFunc func(net.Conn, string, string, string) (bool, error)
-type hostRewriteFunc func(net.Conn, string) (net.Conn, error)
-type successFunc func(net.Conn, map[string]string) error
+type (
+	muxFunc         func(net.Conn) (net.Conn, map[string]string, error)
+	httpAuthFunc    func(net.Conn, string, string, string) (bool, 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.
 type Muxer struct {
@@ -60,7 +62,6 @@ func NewMuxer(
 	rewriteFunc hostRewriteFunc,
 	timeout time.Duration,
 ) (mux *Muxer, err error) {
-
 	mux = &Muxer{
 		listener:       listener,
 		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) {
-
 	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 {
 			return vr.payload.(*Listener), true
 		}
@@ -167,14 +167,14 @@ func (v *Muxer) run() {
 
 func (v *Muxer) handle(c net.Conn) {
 	if err := c.SetDeadline(time.Now().Add(v.timeout)); err != nil {
-		c.Close()
+		_ = c.Close()
 		return
 	}
 
 	sConn, reqInfoMap, err := v.vhostFunc(c)
 	if err != nil {
 		log.Debug("get hostname from http/https request error: %v", err)
-		c.Close()
+		_ = c.Close()
 		return
 	}
 
@@ -184,9 +184,12 @@ func (v *Muxer) handle(c net.Conn) {
 	l, ok := v.getListener(name, path, httpUser)
 	if !ok {
 		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)
-		c.Close()
+		_ = c.Close()
 		return
 	}
 
@@ -194,7 +197,7 @@ func (v *Muxer) handle(c net.Conn) {
 	if v.successFunc != nil {
 		if err := v.successFunc(c, reqInfoMap); err != nil {
 			xl.Info("success func failure on vhost connection: %v", err)
-			c.Close()
+			_ = c.Close()
 			return
 		}
 	}
@@ -203,17 +206,20 @@ func (v *Muxer) handle(c net.Conn) {
 	// then verify user access
 	if l.mux.authFunc != nil && l.userName != "" && l.passWord != "" {
 		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")
 			res := noAuthResponse()
-			res.Write(c)
-			c.Close()
+			if res.Body != nil {
+				defer res.Body.Close()
+			}
+			_ = res.Write(c)
+			_ = c.Close()
 			return
 		}
 	}
 
 	if err = sConn.SetDeadline(time.Time{}); err != nil {
-		c.Close()
+		_ = c.Close()
 		return
 	}
 	c = sConn

+ 12 - 13
server/control.go

@@ -23,6 +23,10 @@ import (
 	"sync"
 	"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/config"
 	"github.com/fatedier/frp/pkg/consts"
@@ -35,10 +39,6 @@ import (
 	"github.com/fatedier/frp/server/controller"
 	"github.com/fatedier/frp/server/metrics"
 	"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 {
@@ -154,7 +154,6 @@ func NewControl(
 	loginMsg *msg.Login,
 	serverCfg config.ServerCommonConf,
 ) *Control {
-
 	poolCount := loginMsg.PoolCount
 	if poolCount > int(serverCfg.MaxPoolCount) {
 		poolCount = int(serverCfg.MaxPoolCount)
@@ -193,7 +192,7 @@ func (ctl *Control) Start() {
 		ServerUDPPort: ctl.serverCfg.BindUDPPort,
 		Error:         "",
 	}
-	msg.WriteMsg(ctl.conn, loginRespMsg)
+	_ = msg.WriteMsg(ctl.conn, loginRespMsg)
 
 	go ctl.writer()
 	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.
-	errors.PanicToError(func() {
+	_ = errors.PanicToError(func() {
 		ctl.sendCh <- &msg.ReqWorkConn{}
 	})
 	return
@@ -388,7 +387,7 @@ func (ctl *Control) stoper() {
 			},
 		}
 		go func() {
-			ctl.pluginManager.CloseProxy(notifyContent)
+			_ = ctl.pluginManager.CloseProxy(notifyContent)
 		}()
 	}
 
@@ -467,7 +466,7 @@ func (ctl *Control) manager() {
 				}
 				ctl.sendCh <- resp
 			case *msg.CloseProxy:
-				ctl.CloseProxy(m)
+				_ = ctl.CloseProxy(m)
 				xl.Info("close proxy [%s] success", m.ProxyName)
 			case *msg.Ping:
 				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")
 			return
 		}
-		ctl.portsUsedNum = ctl.portsUsedNum + pxy.GetUsedPortsNum()
+		ctl.portsUsedNum += pxy.GetUsedPortsNum()
 		ctl.mu.Unlock()
 
 		defer func() {
 			if err != nil {
 				ctl.mu.Lock()
-				ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
+				ctl.portsUsedNum -= pxy.GetUsedPortsNum()
 				ctl.mu.Unlock()
 			}
 		}()
@@ -570,7 +569,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
 	}
 
 	if ctl.serverCfg.MaxPortsPerClient > 0 {
-		ctl.portsUsedNum = ctl.portsUsedNum - pxy.GetUsedPortsNum()
+		ctl.portsUsedNum -= pxy.GetUsedPortsNum()
 	}
 	pxy.Close()
 	ctl.pxyManager.Del(pxy.GetName())
@@ -590,7 +589,7 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
 		},
 	}
 	go func() {
-		ctl.pluginManager.CloseProxy(notifyContent)
+		_ = ctl.pluginManager.CloseProxy(notifyContent)
 	}()
 
 	return

+ 6 - 4
server/dashboard.go

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

+ 7 - 7
server/dashboard_api.go

@@ -18,13 +18,13 @@ import (
 	"encoding/json"
 	"net/http"
 
+	"github.com/gorilla/mux"
+
 	"github.com/fatedier/frp/pkg/config"
 	"github.com/fatedier/frp/pkg/consts"
 	"github.com/fatedier/frp/pkg/metrics/mem"
 	"github.com/fatedier/frp/pkg/util/log"
 	"github.com/fatedier/frp/pkg/util/version"
-
-	"github.com/gorilla/mux"
 )
 
 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)
 		w.WriteHeader(res.Code)
 		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)
 		w.WriteHeader(res.Code)
 		if len(res.Msg) > 0 {
-			w.Write([]byte(res.Msg))
+			_, _ = w.Write([]byte(res.Msg))
 		}
 	}()
 	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)
 		w.WriteHeader(res.Code)
 		if len(res.Msg) > 0 {
-			w.Write([]byte(res.Msg))
+			_, _ = w.Write([]byte(res.Msg))
 		}
 	}()
 	log.Info("Http request: [%s]", r.URL.Path)
 
-	proxyStatsResp := GetProxyStatsResp{}
+	var proxyStatsResp GetProxyStatsResp
 	proxyStatsResp, res.Code, res.Msg = svr.getProxyStatsByTypeAndName(proxyType, name)
 	if res.Code != 200 {
 		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)
 		w.WriteHeader(res.Code)
 		if len(res.Msg) > 0 {
-			w.Write([]byte(res.Msg))
+			_, _ = w.Write([]byte(res.Msg))
 		}
 	}()
 	log.Info("Http request: [%s]", r.URL.Path)

+ 1 - 3
server/group/http.go

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

+ 4 - 5
server/group/tcp.go

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

+ 2 - 5
server/group/tcpmux.go

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

+ 3 - 3
server/proxy/http.go

@@ -19,13 +19,13 @@ import (
 	"net"
 	"strings"
 
+	frpIo "github.com/fatedier/golib/io"
+
 	"github.com/fatedier/frp/pkg/config"
 	frpNet "github.com/fatedier/frp/pkg/util/net"
 	"github.com/fatedier/frp/pkg/util/util"
 	"github.com/fatedier/frp/pkg/util/vhost"
 	"github.com/fatedier/frp/server/metrics"
-
-	frpIo "github.com/fatedier/golib/io"
 )
 
 type HTTPProxy struct {
@@ -89,7 +89,7 @@ func (pxy *HTTPProxy) Run() (remoteAddr string, err error) {
 					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]",
 				routeConfig.Domain, routeConfig.Location, pxy.cfg.Group, pxy.cfg.RouteByHTTPUser)
 		}

+ 1 - 1
server/proxy/https.go

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

+ 4 - 4
server/proxy/proxy.go

@@ -23,6 +23,8 @@ import (
 	"sync"
 	"time"
 
+	frpIo "github.com/fatedier/golib/io"
+
 	"github.com/fatedier/frp/pkg/config"
 	"github.com/fatedier/frp/pkg/msg"
 	plugin "github.com/fatedier/frp/pkg/plugin/server"
@@ -30,8 +32,6 @@ import (
 	"github.com/fatedier/frp/pkg/util/xlog"
 	"github.com/fatedier/frp/server/controller"
 	"github.com/fatedier/frp/server/metrics"
-
-	frpIo "github.com/fatedier/golib/io"
 )
 
 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,
-	getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf) (pxy Proxy, err error) {
-
+	getWorkConnFn GetWorkConnFn, pxyConf config.ProxyConf, serverCfg config.ServerCommonConf,
+) (pxy Proxy, err error) {
 	xl := xlog.FromContextSafe(ctx).Spawn().AppendPrefix(pxyConf.GetBaseInfo().ProxyName)
 	basePxy := BaseProxy{
 		name:          pxyConf.GetBaseInfo().ProxyName,

+ 9 - 7
server/proxy/udp.go

@@ -22,14 +22,14 @@ import (
 	"strconv"
 	"time"
 
+	"github.com/fatedier/golib/errors"
+	frpIo "github.com/fatedier/golib/io"
+
 	"github.com/fatedier/frp/pkg/config"
 	"github.com/fatedier/frp/pkg/msg"
 	"github.com/fatedier/frp/pkg/proto/udp"
 	frpNet "github.com/fatedier/frp/pkg/util/net"
 	"github.com/fatedier/frp/server/metrics"
-
-	"github.com/fatedier/golib/errors"
-	frpIo "github.com/fatedier/golib/io"
 )
 
 type UDPProxy struct {
@@ -98,18 +98,20 @@ func (pxy *UDPProxy) Run() (remoteAddr string, err error) {
 			)
 			xl.Trace("loop waiting message from udp workConn")
 			// 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 {
 				xl.Warn("read from workConn for udp error: %v", errRet)
-				conn.Close()
+				_ = conn.Close()
 				// notify proxy to start a new work connection
 				// ignore error here, it means the proxy is closed
-				errors.PanicToError(func() {
+				_ = errors.PanicToError(func() {
 					pxy.checkCloseCh <- 1
 				})
 				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) {
 			case *msg.Ping:
 				xl.Trace("udp work conn get ping message")

+ 3 - 3
server/proxy/xtcp.go

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

+ 28 - 24
server/service.go

@@ -26,6 +26,9 @@ import (
 	"strconv"
 	"time"
 
+	"github.com/fatedier/golib/net/mux"
+	fmux "github.com/hashicorp/yamux"
+
 	"github.com/fatedier/frp/assets"
 	"github.com/fatedier/frp/pkg/auth"
 	"github.com/fatedier/frp/pkg/config"
@@ -47,9 +50,6 @@ import (
 	"github.com/fatedier/frp/server/ports"
 	"github.com/fatedier/frp/server/proxy"
 	"github.com/fatedier/frp/server/visitor"
-
-	"github.com/fatedier/golib/net/mux"
-	fmux "github.com/hashicorp/yamux"
 )
 
 const (
@@ -127,26 +127,26 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
 		address := net.JoinHostPort(cfg.ProxyBindAddr, strconv.Itoa(cfg.TCPMuxHTTPConnectPort))
 		l, err = net.Listen("tcp", address)
 		if err != nil {
-			err = fmt.Errorf("Create server listener error, %v", err)
+			err = fmt.Errorf("create server listener error, %v", err)
 			return
 		}
 
 		svr.rc.TCPMuxHTTPConnectMuxer, err = tcpmux.NewHTTPConnectTCPMuxer(l, cfg.TCPMuxPassthrough, vhostReadWriteTimeout)
 		if err != nil {
-			err = fmt.Errorf("Create vhost tcpMuxer error, %v", err)
+			err = fmt.Errorf("create vhost tcpMuxer error, %v", err)
 			return
 		}
 		log.Info("tcpmux httpconnect multiplexer listen on %s, passthough: %v", address, cfg.TCPMuxPassthrough)
 	}
 
 	// Init all plugins
-	plugin_names := make([]string, 0, len(cfg.HTTPPlugins))
+	pluginNames := make([]string, 0, len(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]))
 		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))
 	ln, err := net.Listen("tcp", address)
 	if err != nil {
-		err = fmt.Errorf("Create server listener error, %v", err)
+		err = fmt.Errorf("create server listener error, %v", err)
 		return
 	}
 
 	svr.muxer = mux.NewMux(ln)
 	svr.muxer.SetKeepAlive(time.Duration(cfg.TCPKeepAlive) * time.Second)
-	go svr.muxer.Serve()
+	go func() {
+		_ = svr.muxer.Serve()
+	}()
 	ln = svr.muxer.DefaultListener()
 
 	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))
 		svr.kcpListener, err = frpNet.ListenKcp(address)
 		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
 		}
 		log.Info("frps kcp listen on udp %s", address)
@@ -229,11 +231,13 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
 		} else {
 			l, err = net.Listen("tcp", address)
 			if err != nil {
-				err = fmt.Errorf("Create vhost http listener error, %v", err)
+				err = fmt.Errorf("create vhost http listener error, %v", err)
 				return
 			}
 		}
-		go server.Serve(l)
+		go func() {
+			_ = server.Serve(l)
+		}()
 		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))
 			l, err = net.Listen("tcp", address)
 			if err != nil {
-				err = fmt.Errorf("Create server listener error, %v", err)
+				err = fmt.Errorf("create server listener error, %v", err)
 				return
 			}
 			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)
 		if err != nil {
-			err = fmt.Errorf("Create vhost httpsMuxer error, %v", err)
+			err = fmt.Errorf("create vhost httpsMuxer error, %v", err)
 			return
 		}
 	}
@@ -271,7 +275,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
 		address := net.JoinHostPort(cfg.BindAddr, strconv.Itoa(cfg.BindUDPPort))
 		nc, err = nathole.NewController(address)
 		if err != nil {
-			err = fmt.Errorf("Create nat hole controller error, %v", err)
+			err = fmt.Errorf("create nat hole controller error, %v", err)
 			return
 		}
 		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))
 		err = svr.RunDashboardServer(address)
 		if err != nil {
-			err = fmt.Errorf("Create dashboard web server error, %v", err)
+			err = fmt.Errorf("create dashboard web server error, %v", err)
 			return
 		}
 		log.Info("Dashboard listen on %s", address)
@@ -324,13 +328,13 @@ func (svr *Service) handleConnection(ctx context.Context, conn net.Conn) {
 		err    error
 	)
 
-	conn.SetReadDeadline(time.Now().Add(connReadTimeout))
+	_ = conn.SetReadDeadline(time.Now().Add(connReadTimeout))
 	if rawMsg, err = msg.ReadMsg(conn); err != nil {
 		log.Trace("Failed to read message: %v", err)
 		conn.Close()
 		return
 	}
-	conn.SetReadDeadline(time.Time{})
+	_ = conn.SetReadDeadline(time.Time{})
 
 	switch m := rawMsg.(type) {
 	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.
 		if err != nil {
 			xl.Warn("register control error: %v", err)
-			msg.WriteMsg(conn, &msg.LoginResp{
+			_ = msg.WriteMsg(conn, &msg.LoginResp{
 				Version: version.Full(),
 				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:
 		if err = svr.RegisterVisitorConn(conn, m); err != nil {
 			xl.Warn("register visitor conn error: %v", err)
-			msg.WriteMsg(conn, &msg.NewVisitorConnResp{
+			_ = msg.WriteMsg(conn, &msg.NewVisitorConnResp{
 				ProxyName: m.ProxyName,
 				Error:     util.GenerateResponseErrorString("register visitor conn error", err, svr.cfg.DetailedErrorsToClient),
 			})
 			conn.Close()
 		} else {
-			msg.WriteMsg(conn, &msg.NewVisitorConnResp{
+			_ = msg.WriteMsg(conn, &msg.NewVisitorConnResp{
 				ProxyName: m.ProxyName,
 				Error:     "",
 			})
@@ -504,7 +508,7 @@ func (svr *Service) RegisterWorkConn(workConn net.Conn, newMsg *msg.NewWorkConn)
 	}
 	if err != nil {
 		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),
 		})
 		return fmt.Errorf("invalid NewWorkConn with run id [%s]", newMsg.RunID)

+ 4 - 4
server/visitor/visitor.go

@@ -20,10 +20,10 @@ import (
 	"net"
 	"sync"
 
+	frpIo "github.com/fatedier/golib/io"
+
 	frpNet "github.com/fatedier/frp/pkg/util/net"
 	"github.com/fatedier/frp/pkg/util/util"
-
-	frpIo "github.com/fatedier/golib/io"
 )
 
 // 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,
-	useEncryption bool, useCompression bool) (err error) {
-
+	useEncryption bool, useCompression bool,
+) (err error) {
 	vm.mu.RLock()
 	defer vm.mu.RUnlock()
 

+ 14 - 14
test/e2e/basic/basic.go

@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/onsi/ginkgo"
+
 	"github.com/fatedier/frp/pkg/transport"
 	"github.com/fatedier/frp/test/e2e/framework"
 	"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/pkg/port"
 	"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()
 
-	Describe("TCP && UDP", func() {
+	ginkgo.Describe("TCP && UDP", func() {
 		types := []string{"tcp", "udp"}
 		for _, t := range types {
 			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
 				clientConf := consts.DefaultClientConfig
 
@@ -93,8 +93,8 @@ var _ = Describe("[Feature: Basic]", func() {
 		}
 	})
 
-	Describe("HTTP", func() {
-		It("proxy to HTTP server", func() {
+	ginkgo.Describe("HTTP", func() {
+		ginkgo.It("proxy to HTTP server", func() {
 			serverConf := consts.DefaultServerConfig
 			vhostHTTPPort := f.AllocPort()
 			serverConf += fmt.Sprintf(`
@@ -175,8 +175,8 @@ var _ = Describe("[Feature: Basic]", func() {
 		})
 	})
 
-	Describe("HTTPS", func() {
-		It("proxy to HTTPS server", func() {
+	ginkgo.Describe("HTTPS", func() {
+		ginkgo.It("proxy to HTTPS server", func() {
 			serverConf := consts.DefaultServerConfig
 			vhostHTTPSPort := f.AllocPort()
 			serverConf += fmt.Sprintf(`
@@ -237,7 +237,7 @@ var _ = Describe("[Feature: Basic]", func() {
 			framework.ExpectNoError(err)
 			localServer := httpserver.New(
 				httpserver.WithBindPort(localPort),
-				httpserver.WithTlsConfig(tlsConfig),
+				httpserver.WithTLSConfig(tlsConfig),
 				httpserver.WithResponse([]byte("test")),
 			)
 			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"}
 		for _, t := range types {
 			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
 				clientServerConf := consts.DefaultClientConfig
 				clientVisitorConf := consts.DefaultClientConfig
@@ -381,8 +381,8 @@ var _ = Describe("[Feature: Basic]", func() {
 		}
 	})
 
-	Describe("TCPMUX", func() {
-		It("Type tcpmux", func() {
+	ginkgo.Describe("TCPMUX", func() {
+		ginkgo.It("Type tcpmux", func() {
 			serverConf := consts.DefaultServerConfig
 			clientConf := consts.DefaultClientConfig
 

+ 8 - 7
test/e2e/basic/client.go

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

+ 21 - 19
test/e2e/basic/client_server.go

@@ -4,12 +4,12 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/onsi/ginkgo"
+
 	"github.com/fatedier/frp/test/e2e/framework"
 	"github.com/fatedier/frp/test/e2e/framework/consts"
 	"github.com/fatedier/frp/test/e2e/pkg/cert"
 	"github.com/fatedier/frp/test/e2e/pkg/port"
-
-	. "github.com/onsi/ginkgo"
 )
 
 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.
 func defineClientServerTest(desc string, f *framework.Framework, configures *generalTestConfigures) {
-	It(desc, func() {
+	ginkgo.It(desc, func() {
 		runClientServerTest(f, configures)
 	})
 }
 
-var _ = Describe("[Feature: Client-Server]", func() {
+var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
 	f := framework.NewDefaultFramework()
 
-	Describe("Protocol", func() {
+	ginkgo.Describe("Protocol", func() {
 		supportProtocols := []string{"tcp", "kcp", "websocket"}
 		for _, protocol := range supportProtocols {
 			configures := &generalTestConfigures{
@@ -76,7 +76,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
 		}
 	})
 
-	Describe("Authentication", func() {
+	ginkgo.Describe("Authentication", func() {
 		defineClientServerTest("Token Correct", f, &generalTestConfigures{
 			server: "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"}
 		for _, protocol := range supportProtocols {
 			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"}
 
 		var (
@@ -122,7 +122,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
 			serverCrtPath, serverKeyPath string
 			clientCrtPath, clientKeyPath string
 		)
-		JustBeforeEach(func() {
+		ginkgo.JustBeforeEach(func() {
 			generator := &cert.SelfSignedCertGenerator{}
 			artifacts, err := generator.Generate("0.0.0.0")
 			framework.ExpectNoError(err)
@@ -131,7 +131,8 @@ var _ = Describe("[Feature: Client-Server]", func() {
 			serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
 			serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
 			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))
 			clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
 		})
@@ -139,7 +140,7 @@ var _ = Describe("[Feature: Client-Server]", func() {
 		for _, protocol := range supportProtocols {
 			tmp := protocol
 
-			It("one-way authentication: "+tmp, func() {
+			ginkgo.It("one-way authentication: "+tmp, func() {
 				runClientServerTest(f, &generalTestConfigures{
 					server: fmt.Sprintf(`
 						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{
 					server: fmt.Sprintf(`
 						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 (
 			caCrtPath                    string
 			serverCrtPath, serverKeyPath string
 			clientCrtPath, clientKeyPath string
 		)
-		JustBeforeEach(func() {
+		ginkgo.JustBeforeEach(func() {
 			generator := &cert.SelfSignedCertGenerator{}
 			artifacts, err := generator.Generate("example.com")
 			framework.ExpectNoError(err)
@@ -191,12 +192,13 @@ var _ = Describe("[Feature: Client-Server]", func() {
 			serverCrtPath = f.WriteTempFile("server.crt", string(artifacts.Cert))
 			serverKeyPath = f.WriteTempFile("server.key", string(artifacts.Key))
 			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))
 			clientKeyPath = f.WriteTempFile("client.key", string(artifacts.Key))
 		})
 
-		It("mutual authentication", func() {
+		ginkgo.It("mutual authentication", func() {
 			runClientServerTest(f, &generalTestConfigures{
 				server: fmt.Sprintf(`
 				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{
 				server: fmt.Sprintf(`
 				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"}
 		for _, protocol := range supportProtocols {
 			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"}
 		for _, protocol := range supportProtocols {
 			tmp := protocol

+ 12 - 12
test/e2e/basic/cmd.go

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

+ 7 - 7
test/e2e/basic/config.go

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

+ 14 - 14
test/e2e/basic/http.go

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

+ 7 - 7
test/e2e/basic/server.go

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

+ 3 - 3
test/e2e/e2e.go

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

+ 3 - 4
test/e2e/e2e_test.go

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

+ 5 - 5
test/e2e/examples.go

@@ -3,17 +3,17 @@ package e2e
 import (
 	"fmt"
 
+	"github.com/onsi/ginkgo"
+
 	"github.com/fatedier/frp/test/e2e/framework"
 	"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()
 
-	Describe("TCP", func() {
-		It("Expose a TCP echo server", func() {
+	ginkgo.Describe("TCP", func() {
+		ginkgo.It("Expose a TCP echo server", func() {
 			serverConf := consts.DefaultServerConfig
 			clientConf := consts.DefaultClientConfig
 

+ 5 - 5
test/e2e/features/bandwidth_limit.go

@@ -5,18 +5,18 @@ import (
 	"strings"
 	"time"
 
+	"github.com/onsi/ginkgo"
+
 	"github.com/fatedier/frp/test/e2e/framework"
 	"github.com/fatedier/frp/test/e2e/framework/consts"
 	"github.com/fatedier/frp/test/e2e/mock/server/streamserver"
 	"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()
 
-	It("Proxy Bandwidth Limit", func() {
+	ginkgo.It("Proxy Bandwidth Limit", func() {
 		serverConf := consts.DefaultServerConfig
 		clientConf := consts.DefaultClientConfig
 
@@ -40,7 +40,7 @@ var _ = Describe("[Feature: Bandwidth Limit]", func() {
 		framework.NewRequestExpect(f).Port(remotePort).RequestModify(func(r *request.Request) {
 			r.Body([]byte(content)).Timeout(30 * time.Second)
 		}).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())
 	})

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