Files
frp/test/e2e/v1/basic/wire.go
fatedier 0773938d70 feat: bridge mixed wire protocol SUDP payloads (#5347)
SUDP payload codec follows transport wireProtocol; same-protocol v1/v1 and v2/v2 keep raw join; only mixed proxy/visitor protocols use message-aware bridge; no new capability/selection field.
2026-06-01 16:22:34 +08:00

231 lines
6.1 KiB
Go

package basic
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/onsi/ginkgo/v2"
"github.com/fatedier/frp/test/e2e/framework"
"github.com/fatedier/frp/test/e2e/framework/consts"
"github.com/fatedier/frp/test/e2e/pkg/port"
)
var _ = ginkgo.Describe("[Feature: WireProtocol]", func() {
f := framework.NewDefaultFramework()
ginkgo.It("v1 tcp and udp proxies", func() {
serverConf := consts.DefaultServerConfig
tcpPortName := port.GenName("WireV1TCP")
udpPortName := port.GenName("WireV1UDP")
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
transport.wireProtocol = "v1"
[[proxies]]
name = "tcp"
type = "tcp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
[[proxies]]
name = "udp"
type = "udp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
`, framework.TCPEchoServerPort, tcpPortName, framework.UDPEchoServerPort, udpPortName)
f.RunProcesses(serverConf, []string{clientConf})
framework.NewRequestExpect(f).PortName(tcpPortName).Ensure()
framework.NewRequestExpect(f).Protocol("udp").PortName(udpPortName).Ensure()
})
ginkgo.It("v2 tcp and udp proxies", func() {
serverConf := consts.DefaultServerConfig
tcpPortName := port.GenName("WireV2TCP")
udpPortName := port.GenName("WireV2UDP")
clientConf := consts.DefaultClientConfig + fmt.Sprintf(`
transport.wireProtocol = "v2"
[[proxies]]
name = "tcp"
type = "tcp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
[[proxies]]
name = "udp"
type = "udp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
`, framework.TCPEchoServerPort, tcpPortName, framework.UDPEchoServerPort, udpPortName)
f.RunProcesses(serverConf, []string{clientConf})
framework.NewRequestExpect(f).PortName(tcpPortName).Ensure()
framework.NewRequestExpect(f).Protocol("udp").PortName(udpPortName).Ensure()
})
ginkgo.It("v2 stcp visitor", func() {
serverConf := consts.DefaultServerConfig
bindPortName := port.GenName("WireV2STCP")
clientServerConf := consts.DefaultClientConfig + fmt.Sprintf(`
user = "user1"
transport.wireProtocol = "v2"
[[proxies]]
name = "stcp"
type = "stcp"
secretKey = "abc"
localPort = {{ .%s }}
`, framework.TCPEchoServerPort)
clientVisitorConf := consts.DefaultClientConfig + fmt.Sprintf(`
user = "user1"
transport.wireProtocol = "v2"
[[visitors]]
name = "stcp-visitor"
type = "stcp"
serverName = "stcp"
secretKey = "abc"
bindPort = {{ .%s }}
`, bindPortName)
f.RunProcesses(serverConf, []string{clientServerConf, clientVisitorConf})
framework.NewRequestExpect(f).PortName(bindPortName).Ensure()
})
for _, tc := range []struct {
name string
proxyWireConfig string
visitorWireConfig string
extraProxyConfig string
extraVisitorConfig string
}{
{
name: "default sudp visitor",
},
{
name: "v2 sudp visitor",
proxyWireConfig: `transport.wireProtocol = "v2"`,
visitorWireConfig: `transport.wireProtocol = "v2"`,
},
{
name: "mixed sudp proxy v1 visitor v2",
proxyWireConfig: `transport.wireProtocol = "v1"`,
visitorWireConfig: `transport.wireProtocol = "v2"`,
extraProxyConfig: `
transport.useEncryption = true
transport.useCompression = true
`,
extraVisitorConfig: `
transport.useEncryption = true
transport.useCompression = true
`,
},
{
name: "mixed sudp proxy v2 visitor v1",
proxyWireConfig: `transport.wireProtocol = "v2"`,
visitorWireConfig: `transport.wireProtocol = "v1"`,
},
} {
ginkgo.It(tc.name, func() {
serverConf := consts.DefaultServerConfig
bindPortName := port.GenName("WireSUDP")
clientServerConf := consts.DefaultClientConfig + fmt.Sprintf(`
user = "user1"
%s
[[proxies]]
name = "sudp"
type = "sudp"
secretKey = "abc"
localPort = {{ .%s }}
%s
`, tc.proxyWireConfig, framework.UDPEchoServerPort, tc.extraProxyConfig)
clientVisitorConf := consts.DefaultClientConfig + fmt.Sprintf(`
user = "user1"
%s
[[visitors]]
name = "sudp-visitor"
type = "sudp"
serverName = "sudp"
secretKey = "abc"
bindPort = {{ .%s }}
%s
`, tc.visitorWireConfig, bindPortName, tc.extraVisitorConfig)
f.RunProcesses(serverConf, []string{clientServerConf, clientVisitorConf})
framework.NewRequestExpect(f).Protocol("udp").PortName(bindPortName).Ensure()
})
}
ginkgo.It("reports client wire protocol", func() {
webPort := f.AllocPort()
serverConf := consts.DefaultServerConfig + fmt.Sprintf(`
webServer.port = %d
`, webPort)
v1PortName := port.GenName("WireReportV1")
v1ClientConf := consts.DefaultClientConfig + fmt.Sprintf(`
clientID = "wire-v1"
transport.wireProtocol = "v1"
[[proxies]]
name = "v1"
type = "tcp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
`, framework.TCPEchoServerPort, v1PortName)
v2PortName := port.GenName("WireReportV2")
v2ClientConf := consts.DefaultClientConfig + fmt.Sprintf(`
clientID = "wire-v2"
transport.wireProtocol = "v2"
[[proxies]]
name = "v2"
type = "tcp"
localPort = {{ .%s }}
remotePort = {{ .%s }}
`, framework.TCPEchoServerPort, v2PortName)
f.RunProcesses(serverConf, []string{v1ClientConf, v2ClientConf})
framework.NewRequestExpect(f).PortName(v1PortName).Ensure()
framework.NewRequestExpect(f).PortName(v2PortName).Ensure()
expectClientWireProtocol(webPort, "wire-v1", "v1")
expectClientWireProtocol(webPort, "wire-v2", "v2")
})
})
type wireClientInfo struct {
ClientID string `json:"clientID"`
WireProtocol string `json:"wireProtocol"`
}
func expectClientWireProtocol(webPort int, clientID string, wireProtocol string) {
resp, err := http.Get(fmt.Sprintf("http://127.0.0.1:%d/api/clients", webPort))
framework.ExpectNoError(err)
defer resp.Body.Close()
framework.ExpectEqual(resp.StatusCode, 200)
content, err := io.ReadAll(resp.Body)
framework.ExpectNoError(err)
var clients []wireClientInfo
framework.ExpectNoError(json.Unmarshal(content, &clients))
for _, client := range clients {
if client.ClientID == clientID {
framework.ExpectEqual(client.WireProtocol, wireProtocol)
return
}
}
framework.Failf("client %q not found in /api/clients response: %s", clientID, string(content))
}