Compare commits

..
3 Commits
Author SHA1 Message Date
fatedier 9735c53045 feat: bridge mixed wire protocol SUDP payloads
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 12:09:12 +08:00
fatedierandGitHub 8563a5fc74 feat: use wire v2 framing for XTCP NatHoleSid (#5343) 2026-05-29 13:46:28 +08:00
fatedierandGitHub 012d9fb0c5 Merge pull request #5340 from fatedier/design/wire-v2-workconn-message-framing
feat: use wire v2 framing for UDP workConn payload
2026-05-28 18:06:56 +08:00
3 changed files with 8 additions and 56 deletions
+6 -4
View File
@@ -1,9 +1,11 @@
## Features
* `transport.wireProtocol = "v2"` now also applies to UDP-based proxy payloads, including ordinary UDP and SUDP, so their payload framing is consistent with the selected wire protocol.
* Improved SUDP compatibility during mixed `transport.wireProtocol` deployments, allowing frps to bridge payloads between v1/default and v2 SUDP clients.
* XTCP work connection `NatHoleSid` messages now follow the selected `transport.wireProtocol`.
* When `transport.wireProtocol = "v2"` is enabled, ordinary UDP proxy work connection payloads now use wire protocol v2 message framing. This keeps UDP message payloads aligned with the negotiated frpc/frps wire protocol.
* SUDP proxy payloads now also follow the connection wire protocol. SUDP v2 endpoints use wire protocol v2 message framing, while v1/default endpoints continue to use the legacy message codec. When the SUDP proxy frpc and visitor frpc use mixed v1/v2 wire protocols, frps bridges UDPPacket messages between the two codecs.
## Compatibility Notes
* When enabling `transport.wireProtocol = "v2"` for SUDP, upgrade both the proxy and visitor frpc instances first, or keep them on `v1` until both sides are upgraded.
* The default/empty `transport.wireProtocol` and `transport.wireProtocol = "v1"` continue to use the legacy message codec for ordinary UDP and SUDP proxy payloads.
* Raw stream proxy paths such as TCP, HTTP, and STCP remain unframed and are not affected by the UDP/SUDP payload framing change.
* Direct NAT hole UDP sid probing packets are not changed by this release.
* `transport.wireProtocol = "v2"` requires peers to use versions that support the same wire v2 payload semantics. Mixing a newer peer that sends v2-framed UDP or SUDP payloads with an older v2-capable peer that still expects the legacy payload codec can break that proxy traffic. During rolling upgrades, upgrade both SUDP proxy and visitor frpc instances before enabling `transport.wireProtocol = "v2"` for SUDP, or keep those clients on `transport.wireProtocol = "v1"` until both sides are upgraded.
+1 -1
View File
@@ -14,7 +14,7 @@
package version
var version = "0.69.1"
var version = "0.69.0"
func Full() string {
return version
+1 -51
View File
@@ -7,8 +7,6 @@ import (
"io"
"net/http"
"os"
"strconv"
"strings"
"testing"
"time"
@@ -160,7 +158,7 @@ webServer.port = %d
framework.NewRequestExpect(f).PortName(portName).Ensure()
})
ginkgo.It("baseline frps handles current frpc forced to v2 according to baseline support", func() {
ginkgo.It("baseline frps rejects current frpc forced to v2", func() {
portName := port.GenName("CompatBaselineFRPSForcedV2")
clientConf := tcpClientConfig("tcp", portName, `
transport.wireProtocol = "v2"
@@ -172,21 +170,6 @@ transport.wireProtocol = "v2"
consts.DefaultServerConfig,
[]string{clientConf},
)
// frp v0.69.0 added control connection wireProtocol v2 support, so
// baseline frps v0.69.0 and newer should accept a current frpc forced
// to v2. Older known baselines still must reject the unsupported protocol.
// For custom baselines, the version is unknown and the binary may be either
// side of the support boundary, so this versioned expectation is skipped.
supportsV2, knownVersion := baselineSupportsControlWireProtocolV2(compatCtx.BaselineVersion)
if !knownVersion {
ginkgo.Skip(fmt.Sprintf("baseline version %q is not semver; skip versioned forced-v2 expectation", compatCtx.BaselineVersion))
}
if supportsV2 {
framework.NewRequestExpect(f).PortName(portName).Ensure()
return
}
expectProcessExit(clientProcesses[0], 5*time.Second)
framework.NewRequestExpect(f).PortName(portName).ExpectError(true).Ensure()
})
@@ -216,39 +199,6 @@ func expectProcessExit(p *process.Process, timeout time.Duration) {
}
}
func baselineSupportsControlWireProtocolV2(version string) (supports bool, known bool) {
version = strings.TrimPrefix(version, "v")
parts := strings.Split(version, ".")
if len(parts) != 3 {
return false, false
}
major, err := strconv.Atoi(parts[0])
if err != nil {
return false, false
}
minor, err := strconv.Atoi(parts[1])
if err != nil {
return false, false
}
patch, err := strconv.Atoi(parts[2])
if err != nil {
return false, false
}
return compareSemanticVersion(major, minor, patch, 0, 69, 0) >= 0, true
}
func compareSemanticVersion(major, minor, patch int, baseMajor, baseMinor, basePatch int) int {
if major != baseMajor {
return major - baseMajor
}
if minor != baseMinor {
return minor - baseMinor
}
return patch - basePatch
}
type wireClientInfo struct {
ClientID string `json:"clientID"`
WireProtocol string `json:"wireProtocol"`