From e7652f4ccc2c01350ddb0ccf422a2a2d94986215 Mon Sep 17 00:00:00 2001 From: 0x7fff <4812302+blizard863@users.noreply.github.com> Date: Thu, 14 Dec 2023 20:32:40 +0800 Subject: [PATCH 01/12] feat: ssh doc (#3841) * feat: add example * feat: add ssh doc --------- Co-authored-by: int7 --- README.md | 39 +++++++++ conf/frps_full_example.toml | 8 ++ doc/ssh_tunnel_gateway.md | 164 ++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 doc/ssh_tunnel_gateway.md diff --git a/README.md b/README.md index 347636f27a1..d6e1986ea30 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ frp also offers a P2P connect mode. * [Connecting to frps via HTTP PROXY](#connecting-to-frps-via-http-proxy) * [Client Plugins](#client-plugins) * [Server Manage Plugins](#server-manage-plugins) + * [SSH Tunnel Gateway](#ssh-tunnel-gateway) * [Contributing](#contributing) * [Donation](#donation) * [GitHub Sponsors](#github-sponsors) @@ -1169,6 +1170,44 @@ Read the [document](/doc/server_plugin.md). Find more plugins in [gofrp/plugin](https://github.com/gofrp/plugin). +### SSH Tunnel Gateway +*added in v0.53.0* + +frp supports listening to an SSH port on the frps side and achieves TCP protocol proxying through the SSH -R protocol, without relying on frpc. + +```toml +# frps.toml +sshTunnelGateway.bindPort = 2200 +``` + +When running ./frps -c frps.toml, a private key file named .autogen_ssh_key will be automatically created in the current working directory. This generated private key file will be used by the SSH server in frps. + +Executing the command + +```bash +ssh -R :80:127.0.0.1:8080 v0@{frp address} -p 2200 tcp --proxy_name "test-tcp" --remote_port 9090 +``` + +sets up a proxy on frps that forwards the local 8080 service to the port 9090. + +```bash +frp (via SSH) (Ctrl+C to quit) + +User: +ProxyName: test-tcp +Type: tcp +RemoteAddress: :9090 + +``` + +This is equivalent to: + +```bash +frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote_port 9090 +``` + +Find more arguments in [document](/doc/ssh_tunnel_gateway.md). + ## Contributing Interested in getting involved? We would like to help you! diff --git a/conf/frps_full_example.toml b/conf/frps_full_example.toml index d25f6473b35..88cf60ebc66 100644 --- a/conf/frps_full_example.toml +++ b/conf/frps_full_example.toml @@ -143,6 +143,14 @@ udpPacketSize = 1500 # Retention time for NAT hole punching strategy data. natholeAnalysisDataReserveHours = 168 +# ssh tunnel gateway +# If you want to enable this feature, the bindPort parameter is required, while others are optional. +# By default, this feature is disabled. It will be enabled if bindPort is greater than 0. +# sshTunnelGateway.bindPort = 2200 +# sshTunnelGateway.privateKeyFile = "/home/frp-user/.ssh/id_rsa" +# sshTunnelGateway.autoGenPrivateKeyPath = "" +# sshTunnelGateway.authorizedKeysFile = "/home/frp-user/.ssh/authorized_keys" + [[httpPlugins]] name = "user-manager" addr = "127.0.0.1:9000" diff --git a/doc/ssh_tunnel_gateway.md b/doc/ssh_tunnel_gateway.md new file mode 100644 index 00000000000..7f1a3ef9367 --- /dev/null +++ b/doc/ssh_tunnel_gateway.md @@ -0,0 +1,164 @@ +### SSH Tunnel Gateway + +*Added in v0.53.0* + + +### Concept +SSH supports reverse proxy capabilities [rfc](https://www.rfc-editor.org/rfc/rfc4254#page-16). + +frp supports listening on an SSH port on the frps side to achieve TCP protocol proxying using the SSH -R protocol. This mode does not rely on frpc. + +SSH reverse tunneling proxying and proxying SSH ports through frp are two different concepts. SSH reverse tunneling proxying is essentially a basic reverse proxying accomplished by connecting to frps via an SSH client when you don't want to use frpc. + + +```toml +# frps.toml +sshTunnelGateway.bindPort = 0 +sshTunnelGateway.privateKeyFile = "" +sshTunnelGateway.autoGenPrivateKeyPath = "" +sshTunnelGateway.authorizedKeysFile = "" +``` + +| Field | Type | Description | Required | +| :--- | :--- | :--- | :--- | +| bindPort| int | The ssh server port that frps listens on.| Yes | +| privateKeyFile | string | Default value is empty. The private key file used by the ssh server. If it is empty, frps will read the private key file under the autoGenPrivateKeyPath path. It can reuse the /home/user/.ssh/id_rsa file on the local machine, or a custom path can be specified.| No | +| autoGenPrivateKeyPath | string |Default value is ./.autogen_ssh_key. If the file does not exist or its content is empty, frps will automatically generate RSA private key file content and store it in this file.|No| +| authorizedKeysFile | string |Default value is empty. If it is empty, ssh client authentication is not authenticated. If it is not empty, it can implement ssh password-free login authentication. It can reuse the local /home/user/.ssh/authorized_keys file or a custom path can be specified.| No | + + +### Basic Usage +#### Server-side frps + +Minimal configuration: + +```toml +sshTunnelGateway.bindPort = 2200 +``` + +Place the above configuration in frps.toml and run ./frps -c frps.toml. It will listen on port 2200 and accept SSH reverse proxy requests. + +Note: + +1. When using the minimal configuration, a .autogen_ssh_key private key file will be automatically created in the current working directory. The SSH server of frps will use this private key file for encryption and decryption. Alternatively, you can reuse an existing private key file on your local machine, such as /home/user/.ssh/id_rsa. + +2. When running frps in the minimal configuration mode, connecting to frps via SSH does not require authentication. It is strongly recommended to configure a token in frps and specify the token in the SSH command line. + +#### Client-side SSH +The command format is: + +```bash +ssh -R :80:{local_ip:port} v0@{frps_address} -p {frps_ssh_listen_port} {tcp|http|https|stcp|tcpmux} --remote_port {real_remote_port} --proxy_name {proxy_name} --token {frp_token} +``` + +1. --proxy_name is optional, and if left empty, a random one will be generated. +The username for logging in to frps is always "v0" and currently has no significance, i.e., v0@{frps_address}. +2. The server-side proxy listens on the port determined by --remote_port. +3. {tcp|http|https|stcp|tcpmux} supports the complete command parameters, which can be obtained by using --help. For example: ssh -R :80::8080 v0@127.0.0.1 -p 2200 http --help. +4. The token is optional, but for security reasons, it is strongly recommended to configure the token in frps. + +#### TCP Proxy + +```bash +ssh -R :80:127.0.0.1:8080 v0@{frp_address} -p 2200 tcp --proxy_name "test-tcp" --remote_port 9090 +``` + +This sets up a proxy on frps that listens on port 9090 and proxies local service on port 8080. + +```bash +frp (via SSH) (Ctrl+C to quit) + +User: +ProxyName: test-tcp +Type: tcp +RemoteAddress: :9090 +``` + +Equivalent to: + +```bash +frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote_port 9090 +``` + +More parameters can be obtained by executing --help. + + +#### HTTP Proxy + +```bash +ssh -R :80:127.0.0.1:8080 v0@{frp address} -p 2200 http --proxy_name "test-http" --custom_domain test-http.frps.com +``` + +Equivalent to: +```bash +frpc http --proxy_name "test-http" --custom_domain test-http.frps.com +``` + +You can access the HTTP service using the following command: + +curl 'http://test-http.frps.com' + +More parameters can be obtained by executing --help. + + +#### HTTPS/STCP/TCPMUX Proxy +To obtain the usage instructions, use the following command: + +```bash +ssh -R :80:127.0.0.1:8080 v0@{frp address} -p 2200 {https|stcp|tcpmux} --help +``` + + +### Advanced Usage +#### Reusing the id_rsa File on the Local Machine + +```toml +# frps.toml +sshTunnelGateway.bindPort = 2200 +sshTunnelGateway.privateKeyFile = "/home/user/.ssh/id_rsa" +``` + +During the SSH protocol handshake, public keys are exchanged for data encryption. Therefore, the SSH server on the frps side needs to specify a private key file, which can be reused from an existing file on the local machine. If the privateKeyFile field is empty, frps will automatically create an RSA private key file. + + +#### Specifying the Auto-Generated Private Key File Path + +```toml +# frps.toml +sshTunnelGateway.bindPort = 2200 +sshTunnelGateway.autoGenPrivateKeyPath = "/var/frp/ssh-private-key-file" +``` + +frps will automatically create a private key file and store it at the specified path. + +Note: Changing the private key file in frps can cause SSH client login failures. If you need to log in successfully, you can delete the old records from the /home/user/.ssh/known_hosts file. + + +#### Using an Existing authorized_keys File for SSH Public Key Authentication + +```toml +# frps.toml +sshTunnelGateway.bindPort = 2200 +sshTunnelGateway.authorizedKeysFile = "/home/user/.ssh/authorized_keys" +``` + +The authorizedKeysFile is the file used for SSH public key authentication, which contains the public key information for users, with one key per line. + +If authorizedKeysFile is empty, frps won't perform any authentication for SSH clients. Frps does not support SSH username and password authentication. + +You can reuse an existing authorized_keys file on your local machine for client authentication. + +Note: authorizedKeysFile is for user authentication during the SSH login phase, while the token is for frps authentication. These two authentication methods are independent. SSH authentication comes first, followed by frps token authentication. It is strongly recommended to enable at least one of them. If authorizedKeysFile is empty, it is highly recommended to enable token authentication in frps to avoid security risks. + + +#### Using a Custom authorized_keys File for SSH Public Key Authentication + +```toml +# frps.toml +sshTunnelGateway.bindPort = 2200 +sshTunnelGateway.authorizedKeysFile = "/var/frps/custom_authorized_keys_file" +``` + +Specify the path to a custom authorized_keys file. + +Note that changes to the authorizedKeysFile file may result in SSH authentication failures. You may need to re-add the public key information to the authorizedKeysFile. From cc2076970f872abf5508e65d0e428ceb2eb723b9 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 14 Dec 2023 20:54:03 +0800 Subject: [PATCH 02/12] update doc (#3844) --- .github/workflows/golangci-lint.yml | 2 +- .golangci.yml | 2 +- README.md | 23 ++++++++++++++---- doc/ssh_tunnel_gateway.md | 36 +++++++++++++---------------- go.mod | 2 +- 5 files changed, 37 insertions(+), 28 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 98583c77129..9517af535fa 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -22,7 +22,7 @@ jobs: 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.53 + version: v1.55 # Optional: golangci-lint command line arguments. # args: --issues-exit-code=0 diff --git a/.golangci.yml b/.golangci.yml index 18cbaf0be8a..f166e9def62 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ service: - golangci-lint-version: 1.51.x # use the fixed version to not introduce new linters unexpectedly + golangci-lint-version: 1.55.x # use the fixed version to not introduce new linters unexpectedly run: concurrency: 4 diff --git a/README.md b/README.md index d6e1986ea30..4bebb8ab607 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ frp also offers a P2P connect mode. * [Using Environment Variables](#using-environment-variables) * [Split Configures Into Different Files](#split-configures-into-different-files) * [Server Dashboard](#server-dashboard) - * [Admin UI](#admin-ui) + * [Client Admin UI](#client-admin-ui) * [Monitor](#monitor) * [Prometheus](#prometheus) * [Authenticating the Client](#authenticating-the-client) @@ -75,7 +75,7 @@ frp also offers a P2P connect mode. * [Custom Subdomain Names](#custom-subdomain-names) * [URL Routing](#url-routing) * [TCP Port Multiplexing](#tcp-port-multiplexing) - * [Connecting to frps via HTTP PROXY](#connecting-to-frps-via-http-proxy) + * [Connecting to frps via PROXY](#connecting-to-frps-via-proxy) * [Client Plugins](#client-plugins) * [Server Manage Plugins](#server-manage-plugins) * [SSH Tunnel Gateway](#ssh-tunnel-gateway) @@ -510,6 +510,7 @@ includes = ["./confd/*.toml"] ```toml # ./confd/test.toml + [[proxies]] name = "ssh" type = "tcp" @@ -621,6 +622,7 @@ The features are off by default. You can turn on encryption and/or compression: ```toml # frpc.toml + [[proxies]] name = "ssh" type = "tcp" @@ -776,6 +778,7 @@ We would like to try to allow multiple proxies bind a same remote port with diff ```toml # frpc.toml + [[proxies]] name = "ssh" type = "tcp" @@ -881,6 +884,7 @@ This feature is only available for types `tcp`, `http`, `tcpmux` now. ```toml # frpc.toml + [[proxies]] name = "test1" type = "tcp" @@ -916,6 +920,7 @@ With health check type **tcp**, the service port will be pinged (TCPing): ```toml # frpc.toml + [[proxies]] name = "test1" type = "tcp" @@ -935,6 +940,7 @@ With health check type **http**, an HTTP request will be sent to the service and ```toml # frpc.toml + [[proxies]] name = "web" type = "http" @@ -959,6 +965,7 @@ However, speaking of web servers and HTTP requests, your web server might rely o ```toml # frpc.toml + [[proxies]] name = "web" type = "http" @@ -975,6 +982,7 @@ Similar to `Host`, You can override other HTTP request headers with proxy type ` ```toml # frpc.toml + [[proxies]] name = "web" type = "http" @@ -1002,6 +1010,7 @@ Here is an example for https service: ```toml # frpc.toml + [[proxies]] name = "web" type = "https" @@ -1024,6 +1033,7 @@ It can only be enabled when proxy type is http. ```toml # frpc.toml + [[proxies]] name = "web" type = "http" @@ -1048,6 +1058,7 @@ Resolve `*.frps.com` to the frps server's IP. This is usually called a Wildcard ```toml # frpc.toml + [[proxies]] name = "web" type = "http" @@ -1067,6 +1078,7 @@ frp supports forwarding HTTP requests to different backend web services by url r ```toml # frpc.toml + [[proxies]] name = "web01" type = "http" @@ -1152,6 +1164,7 @@ Using plugin **http_proxy**: ```toml # frpc.toml + [[proxies]] name = "http_proxy" type = "tcp" @@ -1171,6 +1184,7 @@ Read the [document](/doc/server_plugin.md). Find more plugins in [gofrp/plugin](https://github.com/gofrp/plugin). ### SSH Tunnel Gateway + *added in v0.53.0* frp supports listening to an SSH port on the frps side and achieves TCP protocol proxying through the SSH -R protocol, without relying on frpc. @@ -1180,7 +1194,7 @@ frp supports listening to an SSH port on the frps side and achieves TCP protocol sshTunnelGateway.bindPort = 2200 ``` -When running ./frps -c frps.toml, a private key file named .autogen_ssh_key will be automatically created in the current working directory. This generated private key file will be used by the SSH server in frps. +When running `./frps -c frps.toml`, a private key file named `.autogen_ssh_key` will be automatically created in the current working directory. This generated private key file will be used by the SSH server in frps. Executing the command @@ -1197,7 +1211,6 @@ User: ProxyName: test-tcp Type: tcp RemoteAddress: :9090 - ``` This is equivalent to: @@ -1206,7 +1219,7 @@ This is equivalent to: frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote_port 9090 ``` -Find more arguments in [document](/doc/ssh_tunnel_gateway.md). +Please refer to this [document](/doc/ssh_tunnel_gateway.md) for more information. ## Contributing diff --git a/doc/ssh_tunnel_gateway.md b/doc/ssh_tunnel_gateway.md index 7f1a3ef9367..b3dd4c34376 100644 --- a/doc/ssh_tunnel_gateway.md +++ b/doc/ssh_tunnel_gateway.md @@ -2,15 +2,14 @@ *Added in v0.53.0* - ### Concept + SSH supports reverse proxy capabilities [rfc](https://www.rfc-editor.org/rfc/rfc4254#page-16). frp supports listening on an SSH port on the frps side to achieve TCP protocol proxying using the SSH -R protocol. This mode does not rely on frpc. SSH reverse tunneling proxying and proxying SSH ports through frp are two different concepts. SSH reverse tunneling proxying is essentially a basic reverse proxying accomplished by connecting to frps via an SSH client when you don't want to use frpc. - ```toml # frps.toml sshTunnelGateway.bindPort = 0 @@ -26,8 +25,8 @@ sshTunnelGateway.authorizedKeysFile = "" | autoGenPrivateKeyPath | string |Default value is ./.autogen_ssh_key. If the file does not exist or its content is empty, frps will automatically generate RSA private key file content and store it in this file.|No| | authorizedKeysFile | string |Default value is empty. If it is empty, ssh client authentication is not authenticated. If it is not empty, it can implement ssh password-free login authentication. It can reuse the local /home/user/.ssh/authorized_keys file or a custom path can be specified.| No | - ### Basic Usage + #### Server-side frps Minimal configuration: @@ -36,26 +35,27 @@ Minimal configuration: sshTunnelGateway.bindPort = 2200 ``` -Place the above configuration in frps.toml and run ./frps -c frps.toml. It will listen on port 2200 and accept SSH reverse proxy requests. +Place the above configuration in frps.toml and run `./frps -c frps.toml`. It will listen on port 2200 and accept SSH reverse proxy requests. Note: -1. When using the minimal configuration, a .autogen_ssh_key private key file will be automatically created in the current working directory. The SSH server of frps will use this private key file for encryption and decryption. Alternatively, you can reuse an existing private key file on your local machine, such as /home/user/.ssh/id_rsa. +1. When using the minimal configuration, a `.autogen_ssh_key` private key file will be automatically created in the current working directory. The SSH server of frps will use this private key file for encryption and decryption. Alternatively, you can reuse an existing private key file on your local machine, such as `/home/user/.ssh/id_rsa`. 2. When running frps in the minimal configuration mode, connecting to frps via SSH does not require authentication. It is strongly recommended to configure a token in frps and specify the token in the SSH command line. #### Client-side SSH + The command format is: ```bash ssh -R :80:{local_ip:port} v0@{frps_address} -p {frps_ssh_listen_port} {tcp|http|https|stcp|tcpmux} --remote_port {real_remote_port} --proxy_name {proxy_name} --token {frp_token} ``` -1. --proxy_name is optional, and if left empty, a random one will be generated. -The username for logging in to frps is always "v0" and currently has no significance, i.e., v0@{frps_address}. -2. The server-side proxy listens on the port determined by --remote_port. -3. {tcp|http|https|stcp|tcpmux} supports the complete command parameters, which can be obtained by using --help. For example: ssh -R :80::8080 v0@127.0.0.1 -p 2200 http --help. -4. The token is optional, but for security reasons, it is strongly recommended to configure the token in frps. +1. `--proxy_name` is optional, and if left empty, a random one will be generated. +2. The username for logging in to frps is always "v0" and currently has no significance, i.e., `v0@{frps_address}`. +3. The server-side proxy listens on the port determined by `--remote_port`. +4. `{tcp|http|https|stcp|tcpmux}` supports the complete command parameters, which can be obtained by using `--help`. For example: `ssh -R :80::8080 v0@127.0.0.1 -p 2200 http --help`. +5. The token is optional, but for security reasons, it is strongly recommended to configure the token in frps. #### TCP Proxy @@ -80,8 +80,7 @@ Equivalent to: frpc tcp --proxy_name "test-tcp" --local_ip 127.0.0.1 --local_port 8080 --remote_port 9090 ``` -More parameters can be obtained by executing --help. - +More parameters can be obtained by executing `--help`. #### HTTP Proxy @@ -100,16 +99,16 @@ curl 'http://test-http.frps.com' More parameters can be obtained by executing --help. - #### HTTPS/STCP/TCPMUX Proxy + To obtain the usage instructions, use the following command: ```bash ssh -R :80:127.0.0.1:8080 v0@{frp address} -p 2200 {https|stcp|tcpmux} --help ``` - ### Advanced Usage + #### Reusing the id_rsa File on the Local Machine ```toml @@ -120,7 +119,6 @@ sshTunnelGateway.privateKeyFile = "/home/user/.ssh/id_rsa" During the SSH protocol handshake, public keys are exchanged for data encryption. Therefore, the SSH server on the frps side needs to specify a private key file, which can be reused from an existing file on the local machine. If the privateKeyFile field is empty, frps will automatically create an RSA private key file. - #### Specifying the Auto-Generated Private Key File Path ```toml @@ -131,8 +129,7 @@ sshTunnelGateway.autoGenPrivateKeyPath = "/var/frp/ssh-private-key-file" frps will automatically create a private key file and store it at the specified path. -Note: Changing the private key file in frps can cause SSH client login failures. If you need to log in successfully, you can delete the old records from the /home/user/.ssh/known_hosts file. - +Note: Changing the private key file in frps can cause SSH client login failures. If you need to log in successfully, you can delete the old records from the `/home/user/.ssh/known_hosts` file. #### Using an Existing authorized_keys File for SSH Public Key Authentication @@ -146,11 +143,10 @@ The authorizedKeysFile is the file used for SSH public key authentication, which If authorizedKeysFile is empty, frps won't perform any authentication for SSH clients. Frps does not support SSH username and password authentication. -You can reuse an existing authorized_keys file on your local machine for client authentication. +You can reuse an existing `authorized_keys` file on your local machine for client authentication. Note: authorizedKeysFile is for user authentication during the SSH login phase, while the token is for frps authentication. These two authentication methods are independent. SSH authentication comes first, followed by frps token authentication. It is strongly recommended to enable at least one of them. If authorizedKeysFile is empty, it is highly recommended to enable token authentication in frps to avoid security risks. - #### Using a Custom authorized_keys File for SSH Public Key Authentication ```toml @@ -159,6 +155,6 @@ sshTunnelGateway.bindPort = 2200 sshTunnelGateway.authorizedKeysFile = "/var/frps/custom_authorized_keys_file" ``` -Specify the path to a custom authorized_keys file. +Specify the path to a custom `authorized_keys` file. Note that changes to the authorizedKeysFile file may result in SSH authentication failures. You may need to re-add the public key information to the authorizedKeysFile. diff --git a/go.mod b/go.mod index d11e1ef4996..4e178fb5393 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/rodaine/table v1.1.0 github.com/samber/lo v1.38.1 github.com/spf13/cobra v1.8.0 + github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 golang.org/x/crypto v0.15.0 golang.org/x/net v0.17.0 @@ -61,7 +62,6 @@ require ( github.com/prometheus/procfs v0.10.1 // indirect github.com/quic-go/qtls-go1-20 v0.3.1 // indirect github.com/rogpeppe/go-internal v1.11.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 From 2d67e2e0c69e93a2465f7c954675247d7c0e3352 Mon Sep 17 00:00:00 2001 From: fatedier Date: Mon, 18 Dec 2023 10:53:02 +0800 Subject: [PATCH 03/12] remove copilot for pr (#3857) --- .github/pull_request_template.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d24eaf818de..7724848141f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,3 @@ -### Summary - -copilot:summary - ### WHY + From 354091087955f6fcb7216ee03a2397376e4526c4 Mon Sep 17 00:00:00 2001 From: Remember <36129334+wuqinqiang@users.noreply.github.com> Date: Thu, 21 Dec 2023 11:43:42 +0800 Subject: [PATCH 04/12] fix(backoff): close of closed out channel (#3871) * fix: close of closed channel * feat: replace Try0 to std --- pkg/util/wait/backoff.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/util/wait/backoff.go b/pkg/util/wait/backoff.go index 45e0ab68a52..048c9591ade 100644 --- a/pkg/util/wait/backoff.go +++ b/pkg/util/wait/backoff.go @@ -16,10 +16,9 @@ package wait import ( "math/rand" + "sync" "time" - "github.com/samber/lo" - "github.com/fatedier/frp/pkg/util/util" ) @@ -182,16 +181,18 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) { func MergeAndCloseOnAnyStopChannel[T any](upstreams ...<-chan T) <-chan T { out := make(chan T) - + closeOnce := sync.Once{} for _, upstream := range upstreams { ch := upstream - go lo.Try0(func() { + go func() { select { case <-ch: - close(out) + closeOnce.Do(func() { + close(out) + }) case <-out: } - }) + }() } return out } From 3bf6605e1a9a252d15df564e9c9e9ac68adc7068 Mon Sep 17 00:00:00 2001 From: im_zhou <32025208+im-zhou@users.noreply.github.com> Date: Thu, 21 Dec 2023 20:51:10 +0800 Subject: [PATCH 05/12] fix: duplicate call loginFunc (#3860) (#3875) modify ext func, specify whether exit immediately --- client/control.go | 6 +++--- client/service.go | 20 ++++++++------------ pkg/util/wait/backoff.go | 10 ++++++---- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/client/control.go b/client/control.go index e4b01ae8c21..edfc726c301 100644 --- a/client/control.go +++ b/client/control.go @@ -239,15 +239,15 @@ func (ctl *Control) heartbeatWorker() { // Users can still enable heartbeat feature by setting HeartbeatInterval to a positive value. if ctl.sessionCtx.Common.Transport.HeartbeatInterval > 0 { // send heartbeat to server - sendHeartBeat := func() error { + sendHeartBeat := func() (bool, error) { xl.Debug("send heartbeat to server") pingMsg := &msg.Ping{} if err := ctl.sessionCtx.AuthSetter.SetPing(pingMsg); err != nil { xl.Warn("error during ping authentication: %v, skip sending ping message", err) - return err + return false, err } _ = ctl.msgDispatcher.Send(pingMsg) - return nil + return false, nil } go wait.BackoffUntil(sendHeartBeat, diff --git a/client/service.go b/client/service.go index c43f8f60497..e8ecc2b5e99 100644 --- a/client/service.go +++ b/client/service.go @@ -192,16 +192,16 @@ func (svr *Service) keepControllerWorking() { // the control immediately exits. It is necessary to limit the frequency of reconnection in this case. // The interval for the first three retries in 1 minute will be very short, and then it will increase exponentially. // The maximum interval is 20 seconds. - wait.BackoffUntil(func() error { + wait.BackoffUntil(func() (bool, error) { // loopLoginUntilSuccess is another layer of loop that will continuously attempt to // login to the server until successful. svr.loopLoginUntilSuccess(20*time.Second, false) if svr.ctl != nil { <-svr.ctl.Done() - return errors.New("control is closed and try another loop") + return false, errors.New("control is closed and try another loop") } // If the control is nil, it means that the login failed and the service is also closed. - return nil + return false, nil }, wait.NewFastBackoffManager( wait.FastBackoffOptions{ Duration: time.Second, @@ -282,9 +282,8 @@ func (svr *Service) login() (conn net.Conn, connector Connector, err error) { func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginExit bool) { xl := xlog.FromContextSafe(svr.ctx) - successCh := make(chan struct{}) - loginFunc := func() error { + loginFunc := func() (bool, error) { xl.Info("try to connect to server...") conn, connector, err := svr.login() if err != nil { @@ -292,7 +291,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE if firstLoginExit { svr.cancel(cancelErr{Err: err}) } - return err + return false, err } svr.cfgMu.RLock() @@ -315,7 +314,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE if err != nil { conn.Close() xl.Error("NewControl error: %v", err) - return err + return false, err } ctl.SetInWorkConnCallback(svr.handleWorkConnCb) @@ -328,8 +327,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE svr.ctl = ctl svr.ctlMu.Unlock() - close(successCh) - return nil + return true, nil } // try to reconnect to server until success @@ -339,9 +337,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE Factor: 2, Jitter: 0.1, MaxDuration: maxInterval, - }), - true, - wait.MergeAndCloseOnAnyStopChannel(svr.ctx.Done(), successCh)) + }), true, svr.ctx.Done()) } func (svr *Service) UpdateAllConfigurer(proxyCfgs []v1.ProxyConfigurer, visitorCfgs []v1.VisitorConfigurer) error { diff --git a/pkg/util/wait/backoff.go b/pkg/util/wait/backoff.go index 048c9591ade..4a0e7e0e4eb 100644 --- a/pkg/util/wait/backoff.go +++ b/pkg/util/wait/backoff.go @@ -113,7 +113,7 @@ func (f *fastBackoffImpl) Backoff(previousDuration time.Duration, previousCondit return f.options.Duration } -func BackoffUntil(f func() error, backoff BackoffManager, sliding bool, stopCh <-chan struct{}) { +func BackoffUntil(f func() (bool, error), backoff BackoffManager, sliding bool, stopCh <-chan struct{}) { var delay time.Duration previousError := false @@ -131,7 +131,9 @@ func BackoffUntil(f func() error, backoff BackoffManager, sliding bool, stopCh < delay = backoff.Backoff(delay, previousError) } - if err := f(); err != nil { + if done, err := f(); done { + return + } else if err != nil { previousError = true } else { previousError = false @@ -170,9 +172,9 @@ func Jitter(duration time.Duration, maxFactor float64) time.Duration { } func Until(f func(), period time.Duration, stopCh <-chan struct{}) { - ff := func() error { + ff := func() (bool, error) { f() - return nil + return false, nil } BackoffUntil(ff, BackoffFunc(func(time.Duration, bool) time.Duration { return period From 5e77c8e2d33317a73282483863c9bdb8e067cd1c Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 21 Dec 2023 21:19:49 +0800 Subject: [PATCH 06/12] fix lint (#3877) --- .golangci.yml | 3 +++ Release.md | 10 +--------- client/service.go | 3 +-- pkg/util/version/version.go | 2 +- pkg/util/wait/backoff.go | 6 ------ 5 files changed, 6 insertions(+), 18 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f166e9def62..8349c9e4aa0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -132,6 +132,9 @@ issues: - linters: - revive text: "unused-parameter" + - linters: + - unparam + text: "is always false" # Independently from option `exclude` we use default exclude patterns, # it can be disabled by this option. To list all diff --git a/Release.md b/Release.md index 8e1ea863ea7..59c4803c92c 100644 --- a/Release.md +++ b/Release.md @@ -1,11 +1,3 @@ -### Features - -* The new command line parameter `--strict_config` has been added to enable strict configuration validation mode. It will throw an error for unknown fields instead of ignoring them. In future versions, we will set the default value of this parameter to true to avoid misconfigurations. -* Support `SSH reverse tunneling`. With this feature, you can expose your local service without running frpc, only using SSH. The SSH reverse tunnel agent has many functional limitations compared to the frpc agent. The currently supported proxy types are tcp, http, https, tcpmux, and stcp. -* The frpc tcpmux command line parameters have been updated to support configuring `http_user` and `http_pwd`. -* The frpc stcp/sudp/xtcp command line parameters have been updated to support configuring `allow_users`. - ### Fixes -* frpc: Return code 1 when the first login attempt fails and exits. -* When auth.method is `oidc` and auth.additionalScopes contains `HeartBeats`, if obtaining AccessToken fails, the application will be unresponsive. +* frpc has a certain chance to panic when login: close of closed channel. diff --git a/client/service.go b/client/service.go index e8ecc2b5e99..74ac419a998 100644 --- a/client/service.go +++ b/client/service.go @@ -326,14 +326,13 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE } svr.ctl = ctl svr.ctlMu.Unlock() - return true, nil } // try to reconnect to server until success wait.BackoffUntil(loginFunc, wait.NewFastBackoffManager( wait.FastBackoffOptions{ - Duration: time.Second, + Duration: time.Millisecond, Factor: 2, Jitter: 0.1, MaxDuration: maxInterval, diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index ab79a55b709..680fbdc96e8 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -19,7 +19,7 @@ import ( "strings" ) -var version = "0.53.0" +var version = "0.53.1" func Full() string { return version diff --git a/pkg/util/wait/backoff.go b/pkg/util/wait/backoff.go index 4a0e7e0e4eb..e07c5316ff6 100644 --- a/pkg/util/wait/backoff.go +++ b/pkg/util/wait/backoff.go @@ -144,12 +144,6 @@ func BackoffUntil(f func() (bool, error), backoff BackoffManager, sliding bool, } ticker.Reset(delay) - select { - case <-stopCh: - return - default: - } - select { case <-stopCh: return From 2a9a7a0e4a64d813c9863d70f2203e06202ef010 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 21 Dec 2023 21:38:32 +0800 Subject: [PATCH 07/12] fix login retry interval (#3879) --- client/service.go | 2 +- pkg/util/version/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/service.go b/client/service.go index 74ac419a998..3d1a21b0e04 100644 --- a/client/service.go +++ b/client/service.go @@ -332,7 +332,7 @@ func (svr *Service) loopLoginUntilSuccess(maxInterval time.Duration, firstLoginE // try to reconnect to server until success wait.BackoffUntil(loginFunc, wait.NewFastBackoffManager( wait.FastBackoffOptions{ - Duration: time.Millisecond, + Duration: time.Second, Factor: 2, Jitter: 0.1, MaxDuration: maxInterval, diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go index 680fbdc96e8..0cdc4b1a344 100644 --- a/pkg/util/version/version.go +++ b/pkg/util/version/version.go @@ -19,7 +19,7 @@ import ( "strings" ) -var version = "0.53.1" +var version = "0.53.2" func Full() string { return version From 5b7b81a117c6cf8695b8546c70d3bb0046df6b8a Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 21 Dec 2023 21:58:56 +0800 Subject: [PATCH 08/12] let e2e concurrency configurable (#3881) --- .gitignore | 2 ++ hack/run-e2e.sh | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c9480d52d3a..0f69b089a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ dist/ .idea/ .vscode/ .autogen_ssh_key +client.crt +client.key # Cache *.swp diff --git a/hack/run-e2e.sh b/hack/run-e2e.sh index a7d4688a7be..d51d0cef91d 100755 --- a/hack/run-e2e.sh +++ b/hack/run-e2e.sh @@ -26,5 +26,9 @@ frpsPath=${ROOT}/bin/frps if [ "${FRPS_PATH}" ]; then frpsPath="${FRPS_PATH}" fi +concurrency="12" +if [ "${CONCURRENCY}" ]; then + concurrency="${CONCURRENCY}" +fi -ginkgo -nodes=8 --poll-progress-after=60s ${ROOT}/test/e2e -- -frpc-path=${frpcPath} -frps-path=${frpsPath} -log-level=${logLevel} -debug=${debug} +ginkgo -nodes=${concurrency} --poll-progress-after=60s ${ROOT}/test/e2e -- -frpc-path=${frpcPath} -frps-path=${frpsPath} -log-level=${logLevel} -debug=${debug} From 256b87321d857b0175e28d8a00d0fadbd1314d92 Mon Sep 17 00:00:00 2001 From: fatedier Date: Thu, 21 Dec 2023 22:46:08 +0800 Subject: [PATCH 09/12] improve e2e port allocator (#3882) --- hack/run-e2e.sh | 2 +- test/e2e/framework/framework.go | 2 +- test/e2e/framework/process.go | 6 +++--- test/e2e/legacy/basic/server.go | 14 +++++++------- test/e2e/pkg/port/port.go | 1 + test/e2e/v1/basic/server.go | 18 +++++++++--------- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/hack/run-e2e.sh b/hack/run-e2e.sh index d51d0cef91d..a574b6db98c 100755 --- a/hack/run-e2e.sh +++ b/hack/run-e2e.sh @@ -26,7 +26,7 @@ frpsPath=${ROOT}/bin/frps if [ "${FRPS_PATH}" ]; then frpsPath="${FRPS_PATH}" fi -concurrency="12" +concurrency="16" if [ "${CONCURRENCY}" ]; then concurrency="${CONCURRENCY}" fi diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index f8b8aa03389..e0be5af14f9 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -67,7 +67,7 @@ func NewDefaultFramework() *Framework { TotalParallelNode: suiteConfig.ParallelTotal, CurrentNodeIndex: suiteConfig.ParallelProcess, FromPortIndex: 10000, - ToPortIndex: 60000, + ToPortIndex: 30000, } return NewFramework(options) } diff --git a/test/e2e/framework/process.go b/test/e2e/framework/process.go index 139753e8d0e..ae89e820078 100644 --- a/test/e2e/framework/process.go +++ b/test/e2e/framework/process.go @@ -42,7 +42,7 @@ func (f *Framework) RunProcesses(serverTemplates []string, clientTemplates []str ExpectNoError(err) time.Sleep(500 * time.Millisecond) } - time.Sleep(1 * time.Second) + time.Sleep(2 * time.Second) currentClientProcesses := make([]*process.Process, 0, len(clientTemplates)) for i := range clientTemplates { @@ -76,7 +76,7 @@ func (f *Framework) RunFrps(args ...string) (*process.Process, string, error) { return p, p.StdOutput(), err } // sleep for a while to get std output - time.Sleep(time.Second) + time.Sleep(2 * time.Second) return p, p.StdOutput(), nil } @@ -87,7 +87,7 @@ func (f *Framework) RunFrpc(args ...string) (*process.Process, string, error) { if err != nil { return p, p.StdOutput(), err } - time.Sleep(time.Second) + time.Sleep(2 * time.Second) return p, p.StdOutput(), nil } diff --git a/test/e2e/legacy/basic/server.go b/test/e2e/legacy/basic/server.go index f3c2a22824e..ca6717c639a 100644 --- a/test/e2e/legacy/basic/server.go +++ b/test/e2e/legacy/basic/server.go @@ -22,11 +22,11 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { clientConf := consts.LegacyDefaultClientConfig serverConf += ` - allow_ports = 20000-25000,25002,30000-50000 + allow_ports = 10000-11000,11002,12000-13000 ` - tcpPortName := port.GenName("TCP", port.WithRangePorts(20000, 25000)) - udpPortName := port.GenName("UDP", port.WithRangePorts(30000, 50000)) + tcpPortName := port.GenName("TCP", port.WithRangePorts(10000, 11000)) + udpPortName := port.GenName("UDP", port.WithRangePorts(12000, 13000)) clientConf += fmt.Sprintf(` [tcp-allowded-in-range] type = tcp @@ -37,7 +37,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { [tcp-port-not-allowed] type = tcp local_port = {{ .%s }} - remote_port = 25001 + remote_port = 11001 `, framework.TCPEchoServerPort) clientConf += fmt.Sprintf(` [tcp-port-unavailable] @@ -55,7 +55,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { [udp-port-not-allowed] type = udp local_port = {{ .%s }} - remote_port = 25003 + remote_port = 11003 `, framework.UDPEchoServerPort) f.RunProcesses([]string{serverConf}, []string{clientConf}) @@ -65,7 +65,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { framework.NewRequestExpect(f).PortName(tcpPortName).Ensure() // Not Allowed - framework.NewRequestExpect(f).Port(25001).ExpectError(true).Ensure() + framework.NewRequestExpect(f).Port(11001).ExpectError(true).Ensure() // Unavailable, already bind by frps framework.NewRequestExpect(f).PortName(consts.PortServerName).ExpectError(true).Ensure() @@ -76,7 +76,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { // Not Allowed framework.NewRequestExpect(f).RequestModify(func(r *request.Request) { - r.UDP().Port(25003) + r.UDP().Port(11003) }).ExpectError(true).Ensure() }) diff --git a/test/e2e/pkg/port/port.go b/test/e2e/pkg/port/port.go index b9bcccfc432..49cc9a68a7e 100644 --- a/test/e2e/pkg/port/port.go +++ b/test/e2e/pkg/port/port.go @@ -79,6 +79,7 @@ func (pa *Allocator) GetByName(portName string) int { udpConn.Close() pa.used.Insert(port) + pa.reserved.Delete(port) return port } return 0 diff --git a/test/e2e/v1/basic/server.go b/test/e2e/v1/basic/server.go index eed1ddaa3f1..f2f4e0a5954 100644 --- a/test/e2e/v1/basic/server.go +++ b/test/e2e/v1/basic/server.go @@ -23,14 +23,14 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { serverConf += ` allowPorts = [ - { start = 20000, end = 25000 }, - { single = 25002 }, - { start = 30000, end = 50000 }, + { start = 10000, end = 11000 }, + { single = 11002 }, + { start = 12000, end = 13000 }, ] ` - tcpPortName := port.GenName("TCP", port.WithRangePorts(20000, 25000)) - udpPortName := port.GenName("UDP", port.WithRangePorts(30000, 50000)) + tcpPortName := port.GenName("TCP", port.WithRangePorts(10000, 11000)) + udpPortName := port.GenName("UDP", port.WithRangePorts(12000, 13000)) clientConf += fmt.Sprintf(` [[proxies]] name = "tcp-allowded-in-range" @@ -43,7 +43,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { name = "tcp-port-not-allowed" type = "tcp" localPort = {{ .%s }} - remotePort = 25001 + remotePort = 11001 `, framework.TCPEchoServerPort) clientConf += fmt.Sprintf(` [[proxies]] @@ -64,7 +64,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { name = "udp-port-not-allowed" type = "udp" localPort = {{ .%s }} - remotePort = 25003 + remotePort = 11003 `, framework.UDPEchoServerPort) f.RunProcesses([]string{serverConf}, []string{clientConf}) @@ -74,7 +74,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { framework.NewRequestExpect(f).PortName(tcpPortName).Ensure() // Not Allowed - framework.NewRequestExpect(f).Port(25001).ExpectError(true).Ensure() + framework.NewRequestExpect(f).Port(11001).ExpectError(true).Ensure() // Unavailable, already bind by frps framework.NewRequestExpect(f).PortName(consts.PortServerName).ExpectError(true).Ensure() @@ -85,7 +85,7 @@ var _ = ginkgo.Describe("[Feature: Server Manager]", func() { // Not Allowed framework.NewRequestExpect(f).RequestModify(func(r *request.Request) { - r.UDP().Port(25003) + r.UDP().Port(11003) }).ExpectError(true).Ensure() }) From cdfa8fa66ffc59a5f3e13ee48c7ac13ef90c9ef2 Mon Sep 17 00:00:00 2001 From: Remember <36129334+wuqinqiang@users.noreply.github.com> Date: Fri, 22 Dec 2023 15:47:59 +0800 Subject: [PATCH 10/12] fix(client): close workConn when authentication err (#3885) --- client/control.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/control.go b/client/control.go index edfc726c301..b272ee06800 100644 --- a/client/control.go +++ b/client/control.go @@ -133,6 +133,7 @@ func (ctl *Control) handleReqWorkConn(_ msg.Message) { } if err = ctl.sessionCtx.AuthSetter.SetNewWorkConn(m); err != nil { xl.Warn("error during NewWorkConn authentication: %v", err) + workConn.Close() return } if err = msg.WriteMsg(workConn, m); err != nil { From 596262d5e043f66b1f97f0dbc55d561d255c5729 Mon Sep 17 00:00:00 2001 From: Remember <36129334+wuqinqiang@users.noreply.github.com> Date: Tue, 26 Dec 2023 10:49:46 +0800 Subject: [PATCH 11/12] upgrade go-jose and crypto version (#3895) --- client/connector.go | 4 ++-- go.mod | 6 +++--- go.sum | 14 +++++++------- pkg/config/v1/proxy.go | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/connector.go b/client/connector.go index ba1441468ee..8c3cd1ec68d 100644 --- a/client/connector.go +++ b/client/connector.go @@ -35,7 +35,7 @@ import ( "github.com/fatedier/frp/pkg/util/xlog" ) -// Connector is a interface for establishing connections to the server. +// Connector is an interface for establishing connections to the server. type Connector interface { Open() error Connect() (net.Conn, error) @@ -59,7 +59,7 @@ func NewConnector(ctx context.Context, cfg *v1.ClientCommonConfig) Connector { } } -// Open opens a underlying connection to the server. +// Open opens an underlying connection to the server. // The underlying connection is either a TCP connection or a QUIC connection. // After the underlying connection is established, you can call Connect() to get a stream. // If TCPMux isn't enabled, the underlying connection is nil, you will get a new real TCP connection every time you call Connect(). diff --git a/go.mod b/go.mod index 4e178fb5393..6253d86b192 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.15.0 + golang.org/x/crypto v0.17.0 golang.org/x/net v0.17.0 golang.org/x/oauth2 v0.10.0 golang.org/x/sync v0.3.0 @@ -39,7 +39,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-jose/go-jose/v3 v3.0.1 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang/mock v1.6.0 // indirect @@ -67,7 +67,7 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.9.3 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 56966be2f0d..2eea0cce4ad 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,8 @@ github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible h1: github.com/fatedier/kcp-go v2.0.4-0.20190803094908-fe8645b0a904+incompatible/go.mod h1:YpCOaxj7vvMThhIQ9AfTOPW2sfztQR5WDfs7AflSy4s= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d h1:ynk1ra0RUqDWQfvFi5KtMiSobkVQ3cNc0ODb8CfIETo= github.com/fatedier/yamux v0.0.0-20230628132301-7aca4898904d/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= @@ -157,8 +157,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= @@ -210,13 +210,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/config/v1/proxy.go b/pkg/config/v1/proxy.go index 8e19d00481c..ec3379ec828 100644 --- a/pkg/config/v1/proxy.go +++ b/pkg/config/v1/proxy.go @@ -195,7 +195,7 @@ type ProxyConfigurer interface { // MarshalToMsg marshals this config into a msg.NewProxy message. This // function will be called on the frpc side. MarshalToMsg(*msg.NewProxy) - // UnmarshalFromMsg unmarshals a msg.NewProxy message into this config. + // UnmarshalFromMsg unmarshal a msg.NewProxy message into this config. // This function will be called on the frps side. UnmarshalFromMsg(*msg.NewProxy) } From d01f4a3ec14e6b011883e8ff5bb4cc5cfb936778 Mon Sep 17 00:00:00 2001 From: fatedier Date: Wed, 27 Dec 2023 10:44:13 +0800 Subject: [PATCH 12/12] cmd: use hyphen instead of underscore (#3898) --- Release.md | 4 ++-- cmd/frpc/sub/root.go | 1 + cmd/frps/root.go | 1 + pkg/config/flags.go | 10 ++++++++++ pkg/ssh/server.go | 2 ++ test/e2e/v1/basic/cmd.go | 4 ++-- test/e2e/v1/features/ssh_tunnel.go | 10 +++++----- 7 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Release.md b/Release.md index 59c4803c92c..1912a3cd5fe 100644 --- a/Release.md +++ b/Release.md @@ -1,3 +1,3 @@ -### Fixes +### Deprecation Notices -* frpc has a certain chance to panic when login: close of closed channel. +* Using an underscore in a flag name is deprecated and has been replaced by a hyphen. The underscore format will remain compatible for some time, until it is completely removed in a future version. For example, `--remote_port` is replaced with `--remote-port`. diff --git a/cmd/frpc/sub/root.go b/cmd/frpc/sub/root.go index fffc49850de..64cac22fff7 100644 --- a/cmd/frpc/sub/root.go +++ b/cmd/frpc/sub/root.go @@ -97,6 +97,7 @@ func runMultipleClients(cfgDir string) error { } func Execute() { + rootCmd.SetGlobalNormalizationFunc(config.WordSepNormalizeFunc) if err := rootCmd.Execute(); err != nil { os.Exit(1) } diff --git a/cmd/frps/root.go b/cmd/frps/root.go index 0cf8e4e79d7..cc083518df1 100644 --- a/cmd/frps/root.go +++ b/cmd/frps/root.go @@ -92,6 +92,7 @@ var rootCmd = &cobra.Command{ } func Execute() { + rootCmd.SetGlobalNormalizationFunc(config.WordSepNormalizeFunc) if err := rootCmd.Execute(); err != nil { os.Exit(1) } diff --git a/pkg/config/flags.go b/pkg/config/flags.go index 712e3d3fba3..98f617be481 100644 --- a/pkg/config/flags.go +++ b/pkg/config/flags.go @@ -17,14 +17,24 @@ package config import ( "fmt" "strconv" + "strings" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/fatedier/frp/pkg/config/types" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/config/v1/validation" ) +// WordSepNormalizeFunc changes all flags that contain "_" separators +func WordSepNormalizeFunc(f *pflag.FlagSet, name string) pflag.NormalizedName { + if strings.Contains(name, "_") { + return pflag.NormalizedName(strings.ReplaceAll(name, "_", "-")) + } + return pflag.NormalizedName(name) +} + type RegisterFlagOption func(*registerFlagOptions) type registerFlagOptions struct { diff --git a/pkg/ssh/server.go b/pkg/ssh/server.go index 264669a3ec3..f3d68f3cf96 100644 --- a/pkg/ssh/server.go +++ b/pkg/ssh/server.go @@ -254,6 +254,8 @@ func (s *TunnelServer) parseClientAndProxyConfigurer(_ *tcpipForward, extraPaylo Short: "ssh v0@{address} [command]", Run: func(*cobra.Command, []string) {}, } + cmd.SetGlobalNormalizationFunc(config.WordSepNormalizeFunc) + args := strings.Split(extraPayload, " ") if len(args) < 1 { return nil, nil, helpMessage, fmt.Errorf("invalid extra payload") diff --git a/test/e2e/v1/basic/cmd.go b/test/e2e/v1/basic/cmd.go index 08a9ea943b9..44aa35990cb 100644 --- a/test/e2e/v1/basic/cmd.go +++ b/test/e2e/v1/basic/cmd.go @@ -90,12 +90,12 @@ var _ = ginkgo.Describe("[Feature: Cmd]", 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)) + _, _, err := f.RunFrps("-t", "123", "-p", strconv.Itoa(serverPort), "--vhost-http-port", strconv.Itoa(vhostHTTPPort)) framework.ExpectNoError(err) _, _, err = f.RunFrpc("http", "-s", "127.0.0.1", "-P", strconv.Itoa(serverPort), "-t", "123", "-u", "test", "-n", "udp_test", "-l", strconv.Itoa(f.PortByName(framework.HTTPSimpleServerPort)), - "--custom_domain", "test.example.com") + "--custom-domain", "test.example.com") framework.ExpectNoError(err) framework.NewRequestExpect(f).Port(vhostHTTPPort). diff --git a/test/e2e/v1/features/ssh_tunnel.go b/test/e2e/v1/features/ssh_tunnel.go index f67d87aaf99..0b8725f6900 100644 --- a/test/e2e/v1/features/ssh_tunnel.go +++ b/test/e2e/v1/features/ssh_tunnel.go @@ -32,7 +32,7 @@ var _ = ginkgo.Describe("[Feature: SSH Tunnel]", func() { tc := ssh.NewTunnelClient( fmt.Sprintf("127.0.0.1:%d", localPort), fmt.Sprintf("127.0.0.1:%d", sshPort), - fmt.Sprintf("tcp --remote_port %d", remotePort), + fmt.Sprintf("tcp --remote-port %d", remotePort), ) framework.ExpectNoError(tc.Start()) defer tc.Close() @@ -55,7 +55,7 @@ var _ = ginkgo.Describe("[Feature: SSH Tunnel]", func() { tc := ssh.NewTunnelClient( fmt.Sprintf("127.0.0.1:%d", localPort), fmt.Sprintf("127.0.0.1:%d", sshPort), - "http --custom_domain test.example.com", + "http --custom-domain test.example.com", ) framework.ExpectNoError(tc.Start()) defer tc.Close() @@ -83,7 +83,7 @@ var _ = ginkgo.Describe("[Feature: SSH Tunnel]", func() { tc := ssh.NewTunnelClient( fmt.Sprintf("127.0.0.1:%d", localPort), fmt.Sprintf("127.0.0.1:%d", sshPort), - fmt.Sprintf("https --custom_domain %s", testDomain), + fmt.Sprintf("https --custom-domain %s", testDomain), ) framework.ExpectNoError(tc.Start()) defer tc.Close() @@ -125,7 +125,7 @@ var _ = ginkgo.Describe("[Feature: SSH Tunnel]", func() { tc := ssh.NewTunnelClient( fmt.Sprintf("127.0.0.1:%d", localPort), fmt.Sprintf("127.0.0.1:%d", sshPort), - fmt.Sprintf("tcpmux --mux=httpconnect --custom_domain %s", testDomain), + fmt.Sprintf("tcpmux --mux=httpconnect --custom-domain %s", testDomain), ) framework.ExpectNoError(tc.Start()) defer tc.Close() @@ -179,7 +179,7 @@ var _ = ginkgo.Describe("[Feature: SSH Tunnel]", func() { tc := ssh.NewTunnelClient( fmt.Sprintf("127.0.0.1:%d", localPort), fmt.Sprintf("127.0.0.1:%d", sshPort), - "stcp -n stcp-test --sk=abcdefg --allow_users=\"*\"", + "stcp -n stcp-test --sk=abcdefg --allow-users=\"*\"", ) framework.ExpectNoError(tc.Start()) defer tc.Close()