Repository: fatedier/frp (language: go)

Issue:
same port for `bindPort` and `vhostHTTPSPort` issue, dashboard https proxy issue
```
# frpc.toml (v0.52.0)

serverAddr = "tunnel.example.com"
serverPort = 5117
user = "user_name"
metadatas.token = "token1"

[[proxies]]
name = "proxy_name"
type = "https"
localIP = "127.0.0.1"
localPort = 3112
subdomain = "test1"
transport.useCompression = false
```

```
# frps.toml (v0.52.0)

bindAddr = "0.0.0.0"
bindPort = 5117
vhostHTTPSPort = 5116
subDomainHost = "tunnel.example.com"

webServer.addr = "0.0.0.0"
webServer.port = 5115
webServer.user = "admin"
webServer.password = "admin"

[[httpPlugins]]
name = "client-authenticator"
addr = "https://login.example.com"
path = "/api/tunnel/auth-frpc"
ops = ["Login"]
#tlsVerify = false
```

- 1st issue: using the same port for `bindPort` and `vhostHTTPSPort` generates:
```
frpc : 2023/10/10 12:06:17 [W] [service.go:131] login to server failed: session shutdown
frps : 2023/10/10 14:35:08 [D] [vhost.go:216] http request for host [tunnel.example.com] path [] httpUser [] not found
```

- 2nd issue: using different ports for `bindPort` and `vhostHTTPSPort` fixes the first issue but generates:
```
frps: 2023/10/10 14:19:11 [W] [dashboard_api.go:214] unmarshal proxy [user_name.proxy_name] conf info error: unknown plugin type: 
```
an open proxy is not listed in the dashboard ui until it is closed


Discussion / hints:
1. [doc](https://github.com/fatedier/frp#tls:~:text=For%20port-,multiplexing,-%2C%20frp%20sends%20a) here. If you want to use same port for `bindPort` and `vhostHTTPSPort`, you should set `transport.tls.disableCustomTLSFirstByte` to false. (There is a bug here, I will fix it later)
2. The issue is same with https://github.com/fatedier/frp/issues/3658, track it there and I will fix it.

Fix patch:
diff --git a/README.md b/README.md
index 7c7656bf522..b560d4473e5 100644
--- a/README.md
+++ b/README.md
@@ -761,6 +761,8 @@ allowPorts = [
 
 `vhostHTTPPort` and `vhostHTTPSPort` in frps can use same port with `bindPort`. frps will detect the connection's protocol and handle it correspondingly.
 
+What you need to pay attention to is that if you want to configure `vhostHTTPSPort` and `bindPort` to the same port, you need to first set `transport.tls.disableCustomTLSFirstByte` to false.
+
 We would like to try to allow multiple proxies bind a same remote port with different protocols in the future.
 
 ### Bandwidth Limit
diff --git a/Release.md b/Release.md
index 95f1ba3648b..3d164f73f43 100644
--- a/Release.md
+++ b/Release.md
@@ -1,9 +1,3 @@
-### Features
+### Fixes
 
-* Configuration: We now support TOML, YAML, and JSON for configuration. Please note that INI is deprecated and will be removed in future releases. New features will only be available in TOML, YAML, or JSON. Users wanting these new features should switch their configuration format accordingly. #2521
-
-### Breaking Changes
-
-* Change the way to start the visitor through the command line from `frpc stcp --role=visitor xxx` to `frpc stcp visitor xxx`.
-* Modified the semantics of the `server_addr` in the command line, no longer including the port. Added the `server_port` parameter to configure the port.
-* No longer support range ports mapping in TOML/YAML/JSON.
+* `transport.tls.disableCustomTLSFirstByte` doesn't have any effect.
diff --git a/client/service.go b/client/service.go
index 5ddc23c3f29..184a87a3305 100644
--- a/client/service.go
+++ b/client/service.go
@@ -476,6 +476,9 @@ func (cm *ConnectionManager) realConnect() (net.Conn, error) {
 		// Make sure that if it is wss, the websocket hook is executed after the tls hook.
 		dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{Hook: utilnet.DialHookWebsocket(protocol, tlsConfig.ServerName), Priority: 110}))
 	default:
+		dialOptions = append(dialOptions, libdial.WithAfterHook(libdial.AfterHook{
+			Hook: utilnet.DialHookCustomTLSHeadByte(tlsConfig != nil, lo.FromPtr(cm.cfg.Transport.TLS.DisableCustomTLSFirstByte)),
+		}))
 		dialOptions = append(dialOptions, libdial.WithTLSConfig(tlsConfig))
 	}
 
diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go
index 32b31837b6f..5f6f3702c50 100644
--- a/pkg/util/version/version.go
+++ b/pkg/util/version/version.go
@@ -19,7 +19,7 @@ import (
 	"strings"
 )
 
-var version = "0.52.0"
+var version = "0.52.1"
 
 func Full() string {
 	return version


Test patch:
diff --git a/test/e2e/v1/basic/client_server.go b/test/e2e/v1/basic/client_server.go
index 082c0de591a..16270781855 100644
--- a/test/e2e/v1/basic/client_server.go
+++ b/test/e2e/v1/basic/client_server.go
@@ -291,7 +291,7 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
 		})
 	})
 
-	ginkgo.Describe("TLS with disable_custom_tls_first_byte set to false", func() {
+	ginkgo.Describe("TLS with disableCustomTLSFirstByte set to false", func() {
 		supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
 		for _, protocol := range supportProtocols {
 			tmp := protocol
@@ -322,4 +322,22 @@ var _ = ginkgo.Describe("[Feature: Client-Server]", func() {
 			})
 		}
 	})
+
+	ginkgo.Describe("Use same port for bindPort and vhostHTTPSPort", func() {
+		supportProtocols := []string{"tcp", "kcp", "quic", "websocket"}
+		for _, protocol := range supportProtocols {
+			tmp := protocol
+			defineClientServerTest("Use same port for bindPort and vhostHTTPSPort: "+strings.ToUpper(tmp), f, &generalTestConfigures{
+				server: fmt.Sprintf(`
+					vhostHTTPSPort = {{ .%s }}
+					%s
+					`, consts.PortServerName, renderBindPortConfig(protocol)),
+				// transport.tls.disableCustomTLSFirstByte should set to false when vhostHTTPSPort is same as bindPort
+				client: fmt.Sprintf(`
+					transport.protocol = "%s"
+					transport.tls.disableCustomTLSFirstByte = false
+					`, protocol),
+			})
+		}
+	})
 })