mirror of
https://github.com/fatedier/frp.git
synced 2024-11-24 02:59:19 +08:00
commit
4bbec09d57
4
.github/workflows/golangci-lint.yml
vendored
4
.github/workflows/golangci-lint.yml
vendored
@ -17,13 +17,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22'
|
go-version: '1.23'
|
||||||
cache: false
|
cache: false
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v4
|
uses: golangci/golangci-lint-action@v4
|
||||||
with:
|
with:
|
||||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
# 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.57
|
version: v1.61
|
||||||
|
|
||||||
# Optional: golangci-lint command line arguments.
|
# Optional: golangci-lint command line arguments.
|
||||||
# args: --issues-exit-code=0
|
# args: --issues-exit-code=0
|
||||||
|
2
.github/workflows/goreleaser.yml
vendored
2
.github/workflows/goreleaser.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.22'
|
go-version: '1.23'
|
||||||
|
|
||||||
- name: Make All
|
- name: Make All
|
||||||
run: |
|
run: |
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
service:
|
service:
|
||||||
golangci-lint-version: 1.57.x # use the fixed version to not introduce new linters unexpectedly
|
golangci-lint-version: 1.61.x # use the fixed version to not introduce new linters unexpectedly
|
||||||
|
|
||||||
run:
|
run:
|
||||||
concurrency: 4
|
concurrency: 4
|
||||||
@ -14,7 +14,7 @@ linters:
|
|||||||
enable:
|
enable:
|
||||||
- unused
|
- unused
|
||||||
- errcheck
|
- errcheck
|
||||||
- exportloopref
|
- copyloopvar
|
||||||
- gocritic
|
- gocritic
|
||||||
- gofumpt
|
- gofumpt
|
||||||
- goimports
|
- goimports
|
||||||
@ -90,6 +90,7 @@ linters-settings:
|
|||||||
- G402
|
- G402
|
||||||
- G404
|
- G404
|
||||||
- G501
|
- G501
|
||||||
|
- G115 # integer overflow conversion
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
# List of regexps of issue texts to exclude, empty list by default.
|
# List of regexps of issue texts to exclude, empty list by default.
|
||||||
|
@ -95,7 +95,7 @@ frp 是一个免费且开源的项目,我们欢迎任何人为其开发和进
|
|||||||
|
|
||||||
您可以通过 [GitHub Sponsors](https://github.com/sponsors/fatedier) 赞助我们。
|
您可以通过 [GitHub Sponsors](https://github.com/sponsors/fatedier) 赞助我们。
|
||||||
|
|
||||||
国内用户可以通过 [爱发电](https://afdian.net/a/fatedier) 赞助我们。
|
国内用户可以通过 [爱发电](https://afdian.com/a/fatedier) 赞助我们。
|
||||||
|
|
||||||
企业赞助者可以将贵公司的 Logo 以及链接放置在项目 README 文件中。
|
企业赞助者可以将贵公司的 Logo 以及链接放置在项目 README 文件中。
|
||||||
|
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
### Features
|
### Features
|
||||||
|
|
||||||
* Added a new plugin `tls2raw`: Enables TLS termination and forwarding of decrypted raw traffic to local service.
|
* The frpc visitor command-line parameter adds the `--server-user` option to specify the username of the server-side proxy to connect to.
|
||||||
* Added a default timeout of 30 seconds for the frpc subcommands to prevent commands from being stuck for a long time due to network issues.
|
* Support multiple frpc instances with different subjects when using oidc authentication.
|
||||||
|
|
||||||
### Fixes
|
|
||||||
|
|
||||||
* Fixed the issue that when `loginFailExit = false`, the frpc stop command cannot be stopped correctly if the server is not successfully connected after startup.
|
|
||||||
|
@ -230,7 +230,7 @@ func (ctl *Control) registerMsgHandlers() {
|
|||||||
ctl.msgDispatcher.RegisterHandler(&msg.Pong{}, ctl.handlePong)
|
ctl.msgDispatcher.RegisterHandler(&msg.Pong{}, ctl.handlePong)
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerWorker sends heartbeat to server and check heartbeat timeout.
|
// heartbeatWorker sends heartbeat to server and check heartbeat timeout.
|
||||||
func (ctl *Control) heartbeatWorker() {
|
func (ctl *Control) heartbeatWorker() {
|
||||||
xl := ctl.xl
|
xl := ctl.xl
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ func (pw *Wrapper) SetRunningStatus(remoteAddr string, respErr string) error {
|
|||||||
pw.Phase = ProxyPhaseStartErr
|
pw.Phase = ProxyPhaseStartErr
|
||||||
pw.Err = respErr
|
pw.Err = respErr
|
||||||
pw.lastStartErr = time.Now()
|
pw.lastStartErr = time.Now()
|
||||||
return fmt.Errorf(pw.Err)
|
return fmt.Errorf("%s", pw.Err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pw.pxy.Run(); err != nil {
|
if err := pw.pxy.Run(); err != nil {
|
||||||
|
@ -327,7 +327,7 @@ requestHeaders.set.x-from-where = "frp"
|
|||||||
|
|
||||||
[[proxies]]
|
[[proxies]]
|
||||||
name = "plugin_tls2raw"
|
name = "plugin_tls2raw"
|
||||||
type = "https"
|
type = "tcp"
|
||||||
remotePort = 6008
|
remotePort = 6008
|
||||||
[proxies.plugin]
|
[proxies.plugin]
|
||||||
type = "tls2raw"
|
type = "tls2raw"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22 AS building
|
FROM golang:1.23 AS building
|
||||||
|
|
||||||
COPY . /building
|
COPY . /building
|
||||||
WORKDIR /building
|
WORKDIR /building
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22 AS building
|
FROM golang:1.23 AS building
|
||||||
|
|
||||||
COPY . /building
|
COPY . /building
|
||||||
WORKDIR /building
|
WORKDIR /building
|
||||||
|
@ -50,7 +50,8 @@ func NewAuthVerifier(cfg v1.AuthServerConfig) (authVerifier Verifier) {
|
|||||||
case v1.AuthMethodToken:
|
case v1.AuthMethodToken:
|
||||||
authVerifier = NewTokenAuth(cfg.AdditionalScopes, cfg.Token)
|
authVerifier = NewTokenAuth(cfg.AdditionalScopes, cfg.Token)
|
||||||
case v1.AuthMethodOIDC:
|
case v1.AuthMethodOIDC:
|
||||||
authVerifier = NewOidcAuthVerifier(cfg.AdditionalScopes, cfg.OIDC)
|
tokenVerifier := NewTokenVerifier(cfg.OIDC)
|
||||||
|
authVerifier = NewOidcAuthVerifier(cfg.AdditionalScopes, tokenVerifier)
|
||||||
}
|
}
|
||||||
return authVerifier
|
return authVerifier
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,18 @@ func (auth *OidcAuthProvider) SetNewWorkConn(newWorkConnMsg *msg.NewWorkConn) (e
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenVerifier interface {
|
||||||
|
Verify(context.Context, string) (*oidc.IDToken, error)
|
||||||
|
}
|
||||||
|
|
||||||
type OidcAuthConsumer struct {
|
type OidcAuthConsumer struct {
|
||||||
additionalAuthScopes []v1.AuthScope
|
additionalAuthScopes []v1.AuthScope
|
||||||
|
|
||||||
verifier *oidc.IDTokenVerifier
|
verifier TokenVerifier
|
||||||
subjectFromLogin string
|
subjectsFromLogin []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCServerConfig) *OidcAuthConsumer {
|
func NewTokenVerifier(cfg v1.AuthOIDCServerConfig) TokenVerifier {
|
||||||
provider, err := oidc.NewProvider(context.Background(), cfg.Issuer)
|
provider, err := oidc.NewProvider(context.Background(), cfg.Issuer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -105,9 +109,14 @@ func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, cfg v1.AuthOIDCSer
|
|||||||
SkipExpiryCheck: cfg.SkipExpiryCheck,
|
SkipExpiryCheck: cfg.SkipExpiryCheck,
|
||||||
SkipIssuerCheck: cfg.SkipIssuerCheck,
|
SkipIssuerCheck: cfg.SkipIssuerCheck,
|
||||||
}
|
}
|
||||||
|
return provider.Verifier(&verifierConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOidcAuthVerifier(additionalAuthScopes []v1.AuthScope, verifier TokenVerifier) *OidcAuthConsumer {
|
||||||
return &OidcAuthConsumer{
|
return &OidcAuthConsumer{
|
||||||
additionalAuthScopes: additionalAuthScopes,
|
additionalAuthScopes: additionalAuthScopes,
|
||||||
verifier: provider.Verifier(&verifierConf),
|
verifier: verifier,
|
||||||
|
subjectsFromLogin: []string{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +125,9 @@ func (auth *OidcAuthConsumer) VerifyLogin(loginMsg *msg.Login) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid OIDC token in login: %v", err)
|
return fmt.Errorf("invalid OIDC token in login: %v", err)
|
||||||
}
|
}
|
||||||
auth.subjectFromLogin = token.Subject
|
if !slices.Contains(auth.subjectsFromLogin, token.Subject) {
|
||||||
|
auth.subjectsFromLogin = append(auth.subjectsFromLogin, token.Subject)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,11 +136,11 @@ func (auth *OidcAuthConsumer) verifyPostLoginToken(privilegeKey string) (err err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid OIDC token in ping: %v", err)
|
return fmt.Errorf("invalid OIDC token in ping: %v", err)
|
||||||
}
|
}
|
||||||
if token.Subject != auth.subjectFromLogin {
|
if !slices.Contains(auth.subjectsFromLogin, token.Subject) {
|
||||||
return fmt.Errorf("received different OIDC subject in login and ping. "+
|
return fmt.Errorf("received different OIDC subject in login and ping. "+
|
||||||
"original subject: %s, "+
|
"original subjects: %s, "+
|
||||||
"new subject: %s",
|
"new subject: %s",
|
||||||
auth.subjectFromLogin, token.Subject)
|
auth.subjectsFromLogin, token.Subject)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
64
pkg/auth/oidc_test.go
Normal file
64
pkg/auth/oidc_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package auth_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc/v3/oidc"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/fatedier/frp/pkg/auth"
|
||||||
|
v1 "github.com/fatedier/frp/pkg/config/v1"
|
||||||
|
"github.com/fatedier/frp/pkg/msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mockTokenVerifier struct{}
|
||||||
|
|
||||||
|
func (m *mockTokenVerifier) Verify(ctx context.Context, subject string) (*oidc.IDToken, error) {
|
||||||
|
return &oidc.IDToken{
|
||||||
|
Subject: subject,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPingWithEmptySubjectFromLoginFails(t *testing.T) {
|
||||||
|
r := require.New(t)
|
||||||
|
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
|
||||||
|
err := consumer.VerifyPing(&msg.Ping{
|
||||||
|
PrivilegeKey: "ping-without-login",
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
})
|
||||||
|
r.Error(err)
|
||||||
|
r.Contains(err.Error(), "received different OIDC subject in login and ping")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPingAfterLoginWithNewSubjectSucceeds(t *testing.T) {
|
||||||
|
r := require.New(t)
|
||||||
|
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
|
||||||
|
err := consumer.VerifyLogin(&msg.Login{
|
||||||
|
PrivilegeKey: "ping-after-login",
|
||||||
|
})
|
||||||
|
r.NoError(err)
|
||||||
|
|
||||||
|
err = consumer.VerifyPing(&msg.Ping{
|
||||||
|
PrivilegeKey: "ping-after-login",
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
})
|
||||||
|
r.NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPingAfterLoginWithDifferentSubjectFails(t *testing.T) {
|
||||||
|
r := require.New(t)
|
||||||
|
consumer := auth.NewOidcAuthVerifier([]v1.AuthScope{v1.AuthScopeHeartBeats}, &mockTokenVerifier{})
|
||||||
|
err := consumer.VerifyLogin(&msg.Login{
|
||||||
|
PrivilegeKey: "login-with-first-subject",
|
||||||
|
})
|
||||||
|
r.NoError(err)
|
||||||
|
|
||||||
|
err = consumer.VerifyPing(&msg.Ping{
|
||||||
|
PrivilegeKey: "ping-with-different-subject",
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
})
|
||||||
|
r.Error(err)
|
||||||
|
r.Contains(err.Error(), "received different OIDC subject in login and ping")
|
||||||
|
}
|
@ -140,6 +140,7 @@ func registerVisitorBaseConfigFlags(cmd *cobra.Command, c *v1.VisitorBaseConfig,
|
|||||||
cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression")
|
cmd.Flags().BoolVarP(&c.Transport.UseCompression, "uc", "", false, "use compression")
|
||||||
cmd.Flags().StringVarP(&c.SecretKey, "sk", "", "", "secret key")
|
cmd.Flags().StringVarP(&c.SecretKey, "sk", "", "", "secret key")
|
||||||
cmd.Flags().StringVarP(&c.ServerName, "server_name", "", "", "server name")
|
cmd.Flags().StringVarP(&c.ServerName, "server_name", "", "", "server name")
|
||||||
|
cmd.Flags().StringVarP(&c.ServerUser, "server-user", "", "", "server user")
|
||||||
cmd.Flags().StringVarP(&c.BindAddr, "bind_addr", "", "", "bind addr")
|
cmd.Flags().StringVarP(&c.BindAddr, "bind_addr", "", "", "bind addr")
|
||||||
cmd.Flags().IntVarP(&c.BindPort, "bind_port", "", 0, "bind port")
|
cmd.Flags().IntVarP(&c.BindPort, "bind_port", "", 0, "bind port")
|
||||||
}
|
}
|
||||||
|
@ -159,18 +159,18 @@ func NewPortsRangeSliceFromString(str string) ([]PortsRange, error) {
|
|||||||
out = append(out, PortsRange{Single: int(singleNum)})
|
out = append(out, PortsRange{Single: int(singleNum)})
|
||||||
case 2:
|
case 2:
|
||||||
// range numbers
|
// range numbers
|
||||||
min, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
minNum, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("range number is invalid, %v", err)
|
return nil, fmt.Errorf("range number is invalid, %v", err)
|
||||||
}
|
}
|
||||||
max, err := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
|
maxNum, err := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("range number is invalid, %v", err)
|
return nil, fmt.Errorf("range number is invalid, %v", err)
|
||||||
}
|
}
|
||||||
if max < min {
|
if maxNum < minNum {
|
||||||
return nil, fmt.Errorf("range number is invalid")
|
return nil, fmt.Errorf("range number is invalid")
|
||||||
}
|
}
|
||||||
out = append(out, PortsRange{Start: int(min), End: int(max)})
|
out = append(out, PortsRange{Start: int(minNum), End: int(maxNum)})
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("range number is invalid")
|
return nil, fmt.Errorf("range number is invalid")
|
||||||
}
|
}
|
||||||
|
@ -78,9 +78,9 @@ func ListAllLocalIPs() ([]net.IP, error) {
|
|||||||
return ips, nil
|
return ips, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListLocalIPsForNatHole(max int) ([]string, error) {
|
func ListLocalIPsForNatHole(maxItems int) ([]string, error) {
|
||||||
if max <= 0 {
|
if maxItems <= 0 {
|
||||||
return nil, fmt.Errorf("max must be greater than 0")
|
return nil, fmt.Errorf("maxItems must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, err := ListAllLocalIPs()
|
ips, err := ListAllLocalIPs()
|
||||||
@ -88,9 +88,9 @@ func ListLocalIPsForNatHole(max int) ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered := make([]string, 0, max)
|
filtered := make([]string, 0, maxItems)
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
if len(filtered) >= max {
|
if len(filtered) >= maxItems {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,21 +85,21 @@ func ParseRangeNumbers(rangeStr string) (numbers []int64, err error) {
|
|||||||
numbers = append(numbers, singleNum)
|
numbers = append(numbers, singleNum)
|
||||||
case 2:
|
case 2:
|
||||||
// range numbers
|
// range numbers
|
||||||
min, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
minValue, errRet := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = fmt.Errorf("range number is invalid, %v", errRet)
|
err = fmt.Errorf("range number is invalid, %v", errRet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
max, errRet := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
|
maxValue, errRet := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
|
||||||
if errRet != nil {
|
if errRet != nil {
|
||||||
err = fmt.Errorf("range number is invalid, %v", errRet)
|
err = fmt.Errorf("range number is invalid, %v", errRet)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if max < min {
|
if maxValue < minValue {
|
||||||
err = fmt.Errorf("range number is invalid")
|
err = fmt.Errorf("range number is invalid")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := min; i <= max; i++ {
|
for i := minValue; i <= maxValue; i++ {
|
||||||
numbers = append(numbers, i)
|
numbers = append(numbers, i)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -118,13 +118,13 @@ func GenerateResponseErrorString(summary string, err error, detailed bool) strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Duration {
|
func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Duration {
|
||||||
min := int64(minRatio * 1000.0)
|
minValue := int64(minRatio * 1000.0)
|
||||||
max := int64(maxRatio * 1000.0)
|
maxValue := int64(maxRatio * 1000.0)
|
||||||
var n int64
|
var n int64
|
||||||
if max <= min {
|
if maxValue <= minValue {
|
||||||
n = min
|
n = minValue
|
||||||
} else {
|
} else {
|
||||||
n = mathrand.Int64N(max-min) + min
|
n = mathrand.Int64N(maxValue-minValue) + minValue
|
||||||
}
|
}
|
||||||
d := duration * time.Duration(n) / time.Duration(1000)
|
d := duration * time.Duration(n) / time.Duration(1000)
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
var version = "0.60.0"
|
var version = "0.61.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
|
@ -137,17 +137,17 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
|
|||||||
dstAddr string
|
dstAddr string
|
||||||
srcPortStr string
|
srcPortStr string
|
||||||
dstPortStr string
|
dstPortStr string
|
||||||
srcPort int
|
srcPort uint64
|
||||||
dstPort int
|
dstPort uint64
|
||||||
)
|
)
|
||||||
|
|
||||||
if src != nil {
|
if src != nil {
|
||||||
srcAddr, srcPortStr, _ = net.SplitHostPort(src.String())
|
srcAddr, srcPortStr, _ = net.SplitHostPort(src.String())
|
||||||
srcPort, _ = strconv.Atoi(srcPortStr)
|
srcPort, _ = strconv.ParseUint(srcPortStr, 10, 16)
|
||||||
}
|
}
|
||||||
if dst != nil {
|
if dst != nil {
|
||||||
dstAddr, dstPortStr, _ = net.SplitHostPort(dst.String())
|
dstAddr, dstPortStr, _ = net.SplitHostPort(dst.String())
|
||||||
dstPort, _ = strconv.Atoi(dstPortStr)
|
dstPort, _ = strconv.ParseUint(dstPortStr, 10, 16)
|
||||||
}
|
}
|
||||||
err := msg.WriteMsg(workConn, &msg.StartWorkConn{
|
err := msg.WriteMsg(workConn, &msg.StartWorkConn{
|
||||||
ProxyName: pxy.GetName(),
|
ProxyName: pxy.GetName(),
|
||||||
@ -190,8 +190,8 @@ func (pxy *BaseProxy) startCommonTCPListenersHandler() {
|
|||||||
} else {
|
} else {
|
||||||
tempDelay *= 2
|
tempDelay *= 2
|
||||||
}
|
}
|
||||||
if max := 1 * time.Second; tempDelay > max {
|
if maxTime := 1 * time.Second; tempDelay > maxTime {
|
||||||
tempDelay = max
|
tempDelay = maxTime
|
||||||
}
|
}
|
||||||
xl.Infof("met temporary error: %s, sleep for %s ...", err, tempDelay)
|
xl.Infof("met temporary error: %s, sleep for %s ...", err, tempDelay)
|
||||||
time.Sleep(tempDelay)
|
time.Sleep(tempDelay)
|
||||||
|
Loading…
Reference in New Issue
Block a user