mirror of
https://github.com/fatedier/frp.git
synced 2025-08-02 12:07:20 +00:00
Compare commits
13 Commits
v0.60.0
...
91058b4568
Author | SHA1 | Date | |
---|---|---|---|
|
91058b4568 | ||
|
dff56cb0ca | ||
|
4383756fd4 | ||
|
6ba849fc75 | ||
|
9d5638cae6 | ||
|
62352c7ba5 | ||
|
f7a06cbe61 | ||
|
3a08c2aeb0 | ||
|
b14192a8d3 | ||
|
2466e65f43 | ||
|
2855ac71e3 | ||
|
fe4ca1b54e | ||
|
edd7cf8967 |
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,10 +1,10 @@
|
|||||||
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
|
||||||
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
# timeout for analysis, e.g. 30s, 5m, default is 1m
|
||||||
deadline: 20m
|
timeout: 20m
|
||||||
build-tags:
|
build-tags:
|
||||||
- integ
|
- integ
|
||||||
- integfuzz
|
- integfuzz
|
||||||
@@ -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.
|
||||||
|
13
README.md
13
README.md
@@ -7,8 +7,17 @@
|
|||||||
|
|
||||||
[README](README.md) | [中文文档](README_zh.md)
|
[README](README.md) | [中文文档](README_zh.md)
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
frp is an open source project with its ongoing development made possible entirely by the support of our awesome sponsors. If you'd like to join them, please consider [sponsoring frp's development](https://github.com/sponsors/fatedier).
|
||||||
|
|
||||||
<h3 align="center">Gold Sponsors</h3>
|
<h3 align="center">Gold Sponsors</h3>
|
||||||
<!--gold sponsors start-->
|
<!--gold sponsors start-->
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://jb.gg/frp" target="_blank">
|
||||||
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_jetbrains.jpg">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
|
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
|
||||||
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
||||||
@@ -20,8 +29,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/beclab/terminus" target="_blank">
|
<a href="https://github.com/beclab/Olares" target="_blank">
|
||||||
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_terminusos.jpeg">
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_olares.jpeg">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<!--gold sponsors end-->
|
<!--gold sponsors end-->
|
||||||
|
15
README_zh.md
15
README_zh.md
@@ -9,8 +9,17 @@
|
|||||||
|
|
||||||
frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。
|
frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。
|
||||||
|
|
||||||
|
## Sponsors
|
||||||
|
|
||||||
|
frp 是一个完全开源的项目,我们的开发工作完全依靠赞助者们的支持。如果你愿意加入他们的行列,请考虑 [赞助 frp 的开发](https://github.com/sponsors/fatedier)。
|
||||||
|
|
||||||
<h3 align="center">Gold Sponsors</h3>
|
<h3 align="center">Gold Sponsors</h3>
|
||||||
<!--gold sponsors start-->
|
<!--gold sponsors start-->
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://jb.gg/frp" target="_blank">
|
||||||
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_jetbrains.jpg">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
|
<a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=frp&utm_source=github" target="_blank">
|
||||||
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_workos.png">
|
||||||
@@ -22,8 +31,8 @@ frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/beclab/terminus" target="_blank">
|
<a href="https://github.com/beclab/Olares" target="_blank">
|
||||||
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_terminusos.jpeg">
|
<img width="420px" src="https://raw.githubusercontent.com/fatedier/frp/dev/doc/pic/sponsor_olares.jpeg">
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<!--gold sponsors end-->
|
<!--gold sponsors end-->
|
||||||
@@ -95,7 +104,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.
|
* `tzdata` is installed by default in the container image, and the time zone can be set using the `TZ` environment variable.
|
||||||
* 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.
|
* The `quic-bind-port` command line parameter is supported in frps, which specifies the port for accepting frpc connections using the QUIC protocol.
|
||||||
|
|
||||||
### 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"
|
||||||
|
BIN
doc/pic/sponsor_jetbrains.jpg
Normal file
BIN
doc/pic/sponsor_jetbrains.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 35 KiB |
BIN
doc/pic/sponsor_olares.jpeg
Normal file
BIN
doc/pic/sponsor_olares.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
Binary file not shown.
Before Width: | Height: | Size: 31 KiB |
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22 AS building
|
FROM golang:1.23 AS building
|
||||||
|
|
||||||
COPY . /building
|
COPY . /building
|
||||||
WORKDIR /building
|
WORKDIR /building
|
||||||
@@ -7,6 +7,8 @@ RUN make frpc
|
|||||||
|
|
||||||
FROM alpine:3
|
FROM alpine:3
|
||||||
|
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
|
||||||
COPY --from=building /building/bin/frpc /usr/bin/frpc
|
COPY --from=building /building/bin/frpc /usr/bin/frpc
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/bin/frpc"]
|
ENTRYPOINT ["/usr/bin/frpc"]
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22 AS building
|
FROM golang:1.23 AS building
|
||||||
|
|
||||||
COPY . /building
|
COPY . /building
|
||||||
WORKDIR /building
|
WORKDIR /building
|
||||||
@@ -7,6 +7,8 @@ RUN make frps
|
|||||||
|
|
||||||
FROM alpine:3
|
FROM alpine:3
|
||||||
|
|
||||||
|
RUN apk add --no-cache tzdata
|
||||||
|
|
||||||
COPY --from=building /building/bin/frps /usr/bin/frps
|
COPY --from=building /building/bin/frps /usr/bin/frps
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/bin/frps"]
|
ENTRYPOINT ["/usr/bin/frps"]
|
||||||
|
@@ -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")
|
||||||
}
|
}
|
||||||
@@ -226,6 +227,7 @@ func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig, opts ...R
|
|||||||
cmd.PersistentFlags().StringVarP(&c.BindAddr, "bind_addr", "", "0.0.0.0", "bind address")
|
cmd.PersistentFlags().StringVarP(&c.BindAddr, "bind_addr", "", "0.0.0.0", "bind address")
|
||||||
cmd.PersistentFlags().IntVarP(&c.BindPort, "bind_port", "p", 7000, "bind port")
|
cmd.PersistentFlags().IntVarP(&c.BindPort, "bind_port", "p", 7000, "bind port")
|
||||||
cmd.PersistentFlags().IntVarP(&c.KCPBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
|
cmd.PersistentFlags().IntVarP(&c.KCPBindPort, "kcp_bind_port", "", 0, "kcp bind udp port")
|
||||||
|
cmd.PersistentFlags().IntVarP(&c.QUICBindPort, "quic_bind_port", "", 0, "quic bind udp port")
|
||||||
cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
|
cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
|
||||||
cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
|
cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
|
||||||
cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")
|
cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https 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)
|
||||||
|
Reference in New Issue
Block a user