Skip to content

Add Auto Transport Mode with IPv4/IPv6 probing and WSS support#5299

Open
ming79486 wants to merge 10 commits intofatedier:devfrom
ming79486:dev
Open

Add Auto Transport Mode with IPv4/IPv6 probing and WSS support#5299
ming79486 wants to merge 10 commits intofatedier:devfrom
ming79486:dev

Conversation

@ming79486
Copy link
Copy Markdown

WHY

This PR adds Auto Transport Mode for frp, allowing frpc and frps to negotiate and select the best transport protocol when both sides set transport.protocol = "auto".

Changes

  • Add client-driven auto transport selection across tcp, kcp, quic, websocket, and wss.
  • Add bootstrap negotiation, server endpoint advertisement, candidate filtering, probing, scoring, and selected transport validation.
  • Add auto transport config parsing, defaults, validation, and backward-compatible legacy config handling.
  • Support the fixed endpoint model:
    • TCP: bindPort
    • KCP: kcpBindPort
    • QUIC: quicBindPort
    • WebSocket/WSS: bindPort
  • Add domain resolution probing for both IPv4 and IPv6 addresses, selecting the fastest usable address/protocol pair.
  • Fix WSS handling by unwrapping TLS first and then processing the WebSocket transport.
  • Add metrics, status reporting, logs, and tests for auto transport behavior.
  • Add minimal auto transport example configs for frps and frpc.

Notes

  • Auto mode is only active when both client and server use transport.protocol = "auto".
  • If transport.proxyURL is configured on the client, candidates are restricted to tcp.
  • QUIC port is configured only on frps; frpc learns it from server advertisement during bootstrap.

Tested

  • go test ./server -count=1
  • go test ./client ./server ./pkg/config/v1 ./pkg/config/v1/validation -count=1
  • go test ./pkg/config ./pkg/config/v1 ./pkg/config/v1/validation -count=1

Comment thread server/auto_transport.go Outdated
Comment thread pkg/metrics/prometheus/server.go Outdated
if protocol == "" {
protocol = "unknown"
}
m.autoRejects.WithLabelValues(protocol).Inc()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Rejected protocol labels are client-controlled

protocol comes from SelectTransport before the client has completed login, so an unauthenticated peer can send many unique values and create unbounded Prometheus time series. Normalize this to a fixed label set, for example known protocols plus unknown, before calling WithLabelValues.

Comment thread pkg/metrics/mem/server.go Outdated
}
m.mu.Lock()
defer m.mu.Unlock()
incCounterMap(m.info.AutoTransportIllegalSelections, protocol, 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Rejected protocol names can grow this map without bound

This key is populated from the pre-login SelectTransport.Protocol value. A client can send arbitrary unique strings and permanently add entries to AutoTransportIllegalSelections, amplifying memory usage and /api/serverinfo responses. Bucket unknown protocols instead of storing the raw value.

Comment thread pkg/config/legacy/conversion.go Outdated
out.Transport.Auto.Enabled = lo.ToPtr(true)
}
out.Transport.Auto.Candidates = conf.AutoCandidates
if conf.AutoAllowUDP {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Legacy auto_allow_udp = false is not preserved

The conversion only sets AllowUDP when the parsed value is true. When a legacy INI config explicitly sets auto_allow_udp = false, this remains nil and ClientAutoTransportConfig.Complete defaults it back to true, so users cannot disable UDP candidates through the legacy config path.

Comment thread pkg/config/legacy/conversion.go Outdated
if conf.AutoEnabled {
out.Transport.Auto.Enabled = lo.ToPtr(true)
}
if conf.AutoAllowDynamicSwitch {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Legacy auto_allow_dynamic_switch = false is not preserved

This only writes AllowDynamicSwitch when the legacy value is true. For an explicit false value, the pointer stays nil and ServerAutoTransportConfig.Complete defaults it to true in auto mode, enabling dynamic switching despite the legacy config.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented Apr 28, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (13 files)
  • client/auto_transport.go
  • pkg/config/legacy/client.go
  • pkg/config/legacy/conversion.go
  • pkg/config/legacy/server.go
  • pkg/config/load_test.go
  • pkg/metrics/mem/server.go
  • pkg/metrics/mem/server_test.go
  • pkg/metrics/prometheus/server.go
  • pkg/msg/msg.go
  • server/auto_transport.go
  • server/auto_transport_test.go
  • server/metrics/metrics.go
  • server/metrics/metrics_test.go

Reviewed by gpt-5.5-20260423 · 570,530 tokens

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants