Commit Graph
100 Commits
Author SHA1 Message Date
fatedier e6e0aaf9d4 fix(vhost): close pending connections when a route listener closes (#5592)
When an HTTPS or tcpmux route listener is closed after a connection has been
resolved to it but before the handoff, Muxer.handle clears the deadline and
then sends on the closed accept channel. The recovered panic returns without
closing the connection, so the peer waits until its own read timeout.

Add a done channel and sync.Once to Listener. Close closes done and is
idempotent; handle and Accept select on accept/done, and a pending connection
is closed when done is closed. Connections already handed to Accept keep their
current ownership. Remove the PanicToError-based control flow.

Cover the pending handoff with net.Pipe and real TCP tests, plus an idempotent
Close test.

Fixes #5573
2026-11-02 14:56:32 +08:00
fatedier 93b52799bb fix(xlog): make Logger prefix updates safe for concurrent logging (#5586)
Logger kept its rendered prefix in a plain string field that was written by
AddPrefix, AppendPrefix and ResetPrefixes and read without synchronization by
Tracef, Spawn and the other logging methods. In frpc the race is reachable on
the service-level logger, which every component of a session shares through
its context: adding the run ID after a login writes the prefix while control,
proxy manager, connector and visitor goroutines keep logging through the same
logger, and a reload that creates proxies calls Spawn on it. A torn string
header can pair a nil data pointer with a non-zero length, and formatting such
a prefix can crash the process when the log call's level is enabled.

Serialize the writers with a per-Logger mutex and publish the rendered prefix
as an immutable string through an atomic pointer, so the log path takes no
lock. Spawn copies the parent prefix list under the same mutex, keeping
children independent snapshots. Logging output is unchanged.
2026-10-23 15:52:11 +08:00
fatedier 8d5e9d2b21 fix(client): use generation-local channels in UDPProxy.InWorkConn (#5585)
InWorkConn published readCh and sendCh into pxy fields while holding
pxy.mu, then read those same fields again after unlocking to start the
sender, reader and heartbeat goroutines and to call udp.Forwarder. Two
work connections installed concurrently made that unlocked read race
with the next generation's write to the same fields.

Create the channels as locals, publish them under the existing lock,
and use only those locals for the goroutines and the forwarder. The
fields stay guarded by pxy.mu, so Close still closes the current
generation. No behavior change for a single generation.

Add TestUDPProxyInWorkConnGenerationChannels, which drives two
InWorkConn calls concurrently so the race detector covers the field
accesses.
2026-10-23 14:03:25 +08:00
fatedier a73e8a14fc docs: track deprecated observability endpoints on webServer (#5582)
Record the deprecation of the observability endpoints on webServer in
doc/deprecations.md, so the removal target is in one place next to the
other active deprecations.

The webServer /healthz, the frps webServer /metrics with its top-level
enablePrometheus switch, and the pprof handlers with webServer.pprofEnable
are deprecated since v0.72.0, when metricsServer was added. They are
replaced by metricsServer, whose /healthz, /metrics and pprofEnable are
independent of the dashboard listener.
2026-10-20 16:51:31 +08:00
fatedier 69ec4f0145 feat(client): serve Go runtime metrics on metricsServer (#5579)
Add pkg/metrics/text, a small Prometheus text-format writer, and use it
for frpc's /metrics. The endpoint lives only on metricsServer and is
covered by its Basic Auth, like the other endpoints there.

The package emits the Go runtime families and, on Linux, the process
families read from /proc. Their names, types and help strings match
client_golang's default collectors, so existing Go runtime dashboards
keep working. It deliberately emits no frp_ business metrics and none of
client_golang's promhttp_ handler metrics.

Writing the subset ourselves keeps client_golang and protobuf out of the
frpc binary; both are still used by frps and by the tests here.
2026-10-20 16:13:38 +08:00
fatedier b0bf32571a ci: pin checkout, setup-go and setup-node to v7 commit SHAs (#5581) 2026-10-20 11:22:34 +08:00
fatedier f13fdd58d4 feat: add metricsServer for health checks, metrics and pprof (#5578)
Add a separate HTTP listener for observability, configured through
metricsServer in both frps and frpc. It serves /healthz and, when
pprofEnable is set, the pprof handlers except /debug/pprof/cmdline. It
never serves the dashboard, static assets or the admin API, and it does
not touch the global assets filesystem.

frps also serves /metrics on this listener with both runtime and business
metrics, enabled by metricsServer.port alone. The in-memory collector
still starts only with the dashboard, and the Prometheus collector starts
either with metricsServer or with enablePrometheus plus webServer, so a
configuration that collected nothing before still collects nothing.

The /healthz, /metrics and pprof endpoints on webServer, and
enablePrometheus, keep working but are deprecated and log a hint at
startup. frpc does not serve /metrics yet.
2026-10-19 20:08:39 +08:00
fatedier 00e4fc4dd3 feat(client): reload plugin certificates on frpc reload (#5576)
The https2http and https2https plugins read their certificate and key
once when the proxy starts, so a certificate that an external tool renews
on disk is only picked up after the proxy itself is recreated. frpc
reload rebuilt proxies only when their configuration changed, and a
rebuild closes the work connections that are already in use.

Let the plugin own the refresh. The HTTPS plugin server keeps the active
keypair and the last refresh error in one immutable snapshot published
through an atomic pointer, so a TLS handshake only loads that pointer and
never touches the disk. Reload rereads both files, and when their bytes
match the published pair it returns without parsing or replacing
anything; otherwise it parses the pair and swaps the snapshot in. A read
or parse failure keeps the previous certificate serving and records the
error next to it.

frpc reload collects the reloadable plugins of the live proxies and
applies the new configuration inside the same reload transaction that
also serializes control handoff, so a reload that races a reconnect
still refreshes the plugins of the published control. The certificate
files are read only after that transaction has been released. The config
store API keeps applying configuration without refreshing certificates,
because only an explicit reload may reread files. Proxy status reports a
refresh failure next to the still running proxy instead of dropping its
remote address.

No configuration field is added, and frps and the wire protocol are
unchanged. Without a reload nothing changes: certificates are still read
once at startup, generated self-signed certificates still never reload,
and a proxy whose configuration changed still goes through the existing
rebuild path.
2026-10-19 17:16:55 +08:00
fatedier 585fdc5b83 fix(client): serialize config updates with control handoff (#5577) 2026-10-19 16:07:07 +08:00
fatedier 228d23b3d5 fix: release pending kcp sessions when the listener is closed (#5575)
KCPListener hands accepted sessions to a consumer through an unbuffered
channel, but its accept goroutine wrote to that channel without watching for
shutdown. A Close racing with a handoff left the goroutine blocked forever,
holding the session it was about to deliver, because closing the underlying
listener does not unblock a send. The close flag it read was also written by
Close without synchronisation.

Watch a done channel in the handoff and close the connection that was never
delivered, so the goroutine can exit and the session is released. Accept now
returns ErrKCPListenerClosed as soon as the listener is closed instead of
blocking on the channel, and the close state is a done channel guarded by
sync.Once.

A ready handoff can still win the race with Close; the session then belongs to
the caller of Accept, matching how WebsocketListener behaves.

Tests cover a pending handoff that is cancelled by Close and a blocked Accept
that is woken by it.
2026-10-19 13:20:00 +08:00
fatedier 399bf2ce4c fix: release listeners when frps fails to start (#5574)
A constructor that binds a port before its fallible preparation leaks the
listener when a later step returns an error, and no one can close it because
the returned service is nil.

pkg/util/http: load the TLS keypair and build the auth middleware before
net.Listen, so binding is the last step that can run and a failure leaves no
bound port behind.

server: create the web server after auth, the tcpmux, main, kcp, quic, ssh
gateway and vhost listeners, and the nat hole controller, following what frpc
already does. If the web server itself fails, close the resources created so
far before returning. The port managers start their cleanup workers on
creation, so they are created after every fallible step too, and the metrics
collectors keep being enabled only when the web server is configured.

Add regression tests for all three failure paths.
2026-10-19 12:20:25 +08:00
fatedier 26742060b1 feat(client): add useSystemCa and combine it with trustedCaFile (#5572)
Move the frpc-only TLS option into the shared TLSConfig as
transport.tls.useSystemCa, replacing the unpublished useSystemRoots.
When set, frpc verifies the server with the system CAs; when
trustedCaFile is also set, its CAs are appended to the system pool so
both are trusted. Failures to load either source abort the connection
instead of falling back. Enabling the option without effective TLS is a
configuration error, and the field is rejected in frps transport.tls
and in both webServer.tls sections.

Fixes #5545
2026-10-18 16:00:02 +08:00
fatedier 954f918d0c docs: clear release notes (#5570) 2026-10-15 23:25:45 +08:00
fatedier 031716afd1 Merge pull request #5569 from fatedier/fix/docker-workspace-lockfile
fix(docker): install web dependencies from the workspace lockfile
2026-10-15 13:01:59 +08:00
fatedier 41ed2aecf8 test: align UDP compatibility protocol boundaries (#5567) 2026-10-14 10:49:55 +08:00
fatedier 12b0093ccf chore: prepare v0.71.1 release notes (#5564) 2026-10-13 10:46:29 +08:00
fatedier 2542d11a62 fix(net): coordinate websocket handoff with listener shutdown (#5563) 2026-10-10 19:58:05 +08:00
fatedier 1cc2dd8a23 fix(vhost): avoid request body access after CONNECT hijack (#5562) 2026-10-09 23:53:05 +08:00
fatedier 1dbd44edd3 fix(msg): interrupt control reads during dispatcher shutdown (#5561) 2026-10-09 17:46:31 +08:00
fatedier 55107d003d fix: synchronize service startup and shutdown (#5560) 2026-10-09 12:27:12 +08:00
fatedier 4cd4747525 fix: use Go 1.26 new expressions for pointer initialization (#5559) 2026-10-08 22:28:31 +08:00
fatedier d20a232996 test: strengthen health check coverage (#5528) 2026-09-10 01:28:26 +08:00
fatedier b0d840858f ci: upgrade CircleCI config to 2.1 (#5530) 2026-09-10 00:17:12 +08:00
fatedier c5508627c4 docs: add rapidproxy as gold sponsor (#5529) 2026-09-10 00:02:51 +08:00
fatedier ebb4773c2c docs: update release notes (#5521) 2026-08-29 14:41:43 +08:00
fatedier 23ec9b4979 vnet: serialize VirtualNet route lifecycle (#5512)
* vnet: serialize virtual net route lifecycle

* test: remove fixed virtual net helper parameters
2026-08-28 10:56:05 +08:00
fatedier 758f07d59e deps: migrate to fatedier/yamux v0.2.0 (#5498) 2026-08-18 00:24:11 +08:00
fatedier 25a4ba306a ci: pin golangci-lint to v2.12.2 (#5496) 2026-08-17 00:48:09 +08:00
fatedier 6c8a8d0a97 web: patch vulnerable transitive dependencies (#5490) 2026-08-13 01:12:34 +08:00
fatedier da04e1e07a log: improve prefix handling (#5489) 2026-08-12 23:56:00 +08:00
fatedier 71a2bf30f9 docs: add release note for domain validation fix (#5475) 2026-08-09 23:04:09 +08:00
fatedier a6a782bed4 config: reject case-insensitive subdomain domains (#5474) 2026-08-09 22:52:30 +08:00
fatedier 223b44336c ssh: serialize tunnel channel writes (#5473) 2026-08-09 19:12:12 +08:00
fatedier f6688e2a0d client: reject invalid work connection addresses (#5472) 2026-08-09 18:39:21 +08:00
fatedier f666d97b64 limit: clamp bandwidth limiter burst (#5471) 2026-08-09 17:30:39 +08:00
fatedier 5b68148f11 udp: handle closed forwarding channel (#5470) 2026-08-09 15:31:11 +08:00
fatedier 1a3a872bd2 fix(frpc): respect feature gates in verify (#5465) 2026-08-04 12:53:10 +08:00
fatedier 290017cb53 update version to 0.71.0 (#5464) 2026-08-03 23:37:36 +08:00
fatedier 2291e8835f feat: use binary codec for SUDP packets (#5461) 2026-07-31 16:53:16 +08:00
fatedier 1ab59e763c server: validate control pool counts (#5459) 2026-07-30 23:30:16 +08:00
fatedier 9d45a55720 docs: add release note for #5456 (#5458) 2026-07-30 14:40:54 +08:00
fatedier effa496859 feat: add negotiated binary UDP packets (#5456) 2026-07-30 13:19:55 +08:00
fatedier 5c6d761c12 chore(web): upgrade frontend dependencies (#5454) 2026-07-28 19:36:44 +08:00
fatedier 3d89ab7ff1 build(web): upgrade auto import plugins (#5453) 2026-07-28 17:09:46 +08:00
fatedier f3828cbfdb build(web): upgrade ESLint to v10 (#5452) 2026-07-28 16:10:29 +08:00
fatedier 00c24e39bb test(web): add frontend unit test baseline (#5451) 2026-07-28 01:27:35 +08:00
fatedier 2175557d48 web: fix Vite config tsconfig includes (#5450) 2026-07-27 19:21:28 +08:00
fatedier de4b483710 web: patch vulnerable transitive dependencies (#5449) 2026-07-27 14:57:58 +08:00
fatedier 2d63f6b1f9 web/frpc: fix visitor plugin validation for sudp (#5448) 2026-07-27 12:04:00 +08:00
fatedier 18eef83b69 fix(client): synchronize graceful shutdown duration (#5442) 2026-07-23 13:55:00 +08:00
fatedier 466a94f5d1 update quic-go dependency to v0.60.0 (#5443) 2026-07-23 12:28:10 +08:00
fatedier 0e53833a2c refactor: use standard library HKDF (#5440) 2026-07-23 01:17:37 +08:00
fatedier c23934bb67 web: update vulnerable transitive dependencies (#5441) 2026-07-23 01:16:40 +08:00
fatedier 23512f577e fix: upgrade go-oidc to v3.18.0 (#5439) 2026-07-23 00:00:47 +08:00
fatedier 84b907a198 deps: bump golib to v0.8.1 (#5437) 2026-07-22 21:47:36 +08:00
fatedier f8fc3c6b1b server: drop HTTP/1.1 h2c upgrade handling (#5436)
Use net/http Server.Protocols and the merged golib listener path instead of the deprecated h2c handler. Keep HTTP/1.1 and cleartext HTTP/2 prior-knowledge support, while intentionally dropping HTTP/1.1 Upgrade: h2c.
2026-07-22 19:55:42 +08:00
fatedier 7dc7be930e ssh: fix malformed exec payload panic (#5428) 2026-07-21 23:04:56 +08:00
fatedier d486018885 fix(server): prevent control replacement lifecycle leaks (#5424) 2026-07-21 18:09:09 +08:00
fatedier fe79598ee4 fix: fail fast on cross-compile errors (#5420) 2026-07-16 16:40:48 +08:00
fatedier 269a26c5d5 fix(nathole): migrate STUN client to golib (#5419) 2026-07-16 13:11:45 +08:00
fatedier 2886393f5b ci: remove unsupported s390x image target (#5412) 2026-07-11 22:44:45 +08:00
fatedier 5396947c7c remove retired Go Report Card badge (#5409) 2026-07-11 15:59:51 +08:00
fatedier fe61093bc2 bump version to 0.70.0 (#5406) 2026-07-11 14:28:19 +08:00
fatedier 54aeb2a7b0 feat(server): add typed frps v2 proxy specs (#5405) 2026-07-11 10:34:04 +08:00
fatedier 84be1938e4 api: expose v2 proxy timestamps as unix seconds (#5402) 2026-07-09 14:47:19 +08:00
fatedier becee40715 docs: update API v2 release notes (#5400) 2026-07-08 15:54:16 +08:00
fatedier 17e788d43b refactor: clean up frps v2 frontend models (#5399) 2026-07-08 13:10:55 +08:00
fatedier 68509f5d44 Add frps proxy traffic API v2 (#5398) 2026-07-08 02:05:28 +08:00
fatedier 5cd722b177 feat: add system prune API v2 (#5395) 2026-07-07 13:00:53 +08:00
fatedier 5876beceac feat: add system info API v2 (#5394) 2026-07-07 02:00:44 +08:00
fatedier 7fe152e3aa web/frps: use API v2 for client and proxy details (#5386) 2026-06-30 01:33:57 +08:00
fatedier 7c343fc6e7 web: bump esbuild to 0.28.1 and remove unused ElPopover type (#5385) 2026-06-29 23:21:22 +08:00
fatedier a3b3b35b69 feat(ui): default proxies view to all tab (#5384) 2026-06-29 22:49:08 +08:00
fatedier ae1c0504ec feat(dashboard): add v2 client detail status (#5381) 2026-06-26 21:15:30 +08:00
fatedier 393a533744 docs: add release note for duplicate config names (#5379) 2026-06-24 15:03:22 +08:00
fatedier 940bde5c46 docs: update release notes (#5377) 2026-06-23 17:06:16 +08:00
fatedier 14628df63c test: cover tls2raw proxy protocol header (#5376) 2026-06-23 00:04:38 +08:00
fatedier 54c6ccdfec feat: remove proxies client filter (#5375) 2026-06-22 22:53:57 +08:00
fatedier 9bde0b07de feat: paginate dashboard clients and proxies via API v2 (#5354)
Move the frps dashboard Clients and Proxies views to the paginated
/api/v2/clients and /api/v2/proxies endpoints instead of fetching all
data at once, and extend server-side proxy search so the search box
keeps working under pagination.

Frontend:
- Add V2Envelope/V2Page types and getV2 HTTP helper to api/http.ts
- Add v2 paginated fetch functions to api/client.ts and api/proxy.ts
- Add ClientV2Info and ProxyV2Info types for v2 API responses
- Rewrite Clients.vue with server-side pagination, status/user search
  filtering, and ElPagination component
- Rewrite Proxies.vue with server-side pagination, type tabs, client
  dropdown filter, and a search box that passes q to the API
- Default page size 10, selectable sizes [10, 20, 50, 100]

Backend:
- Extend /api/v2/proxies q matching to also cover online proxy spec
  fields: TCP/UDP remotePort and HTTP/HTTPS/TCPMux customDomains and
  subdomain, so dashboard search no longer needs to scan every page
- Add controller_v2 tests for the new spec-field matching
2026-06-03 14:08:45 +08:00
fatedier c6c545289c fix: normalize web package lockfile (#5353) 2026-06-02 13:39:37 +08:00
fatedier 503afe78b7 feat: add dashboard API v2 pagination endpoints (#5351) 2026-06-01 20:09:25 +08:00
fatedier 9ea1d86f03 test: handle wire v2 compatibility baselines (#5349) 2026-06-01 17:52:57 +08:00
fatedier ac3e82db4e Release v0.69.1 (#5348) 2026-06-01 16:22:34 +08:00
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
fatedier 9bacce22a2 feat: use wire v2 framing for XTCP NatHoleSid (#5343) 2026-06-01 16:22:34 +08:00
fatedier 7f8d68b666 feat: use wire v2 framing for UDP workConn payload (#5340) 2026-06-01 16:22:34 +08:00
fatedier 3e19ef9bfd feat(ui): add xtcp tab to frps dashboard (#5322) 2026-05-21 22:18:00 +08:00
fatedier e20f974d61 feat(ui): add all proxies tab to frps dashboard (#5321) 2026-05-20 16:20:58 +08:00
fatedier a88e0e9a49 refactor: clean up code (#5308) 2026-05-12 11:13:50 +08:00
fatedier 8666e3643f protocol: add AEAD encryption negotiation to v2 wire control channel (#5304) 2026-05-06 10:43:47 +08:00
fatedier 57bb9e80fe test/e2e: add compatibility test suite for wire protocol version negotiation (#5297) 2026-04-27 18:28:22 +08:00
fatedier cef71fb949 plugin/http_proxy: fix fragmented CONNECT method detection and add read deadline (#5296) 2026-04-27 02:30:29 +08:00
fatedier 410c4861c4 update Release.md (#5295) 2026-04-27 01:31:10 +08:00
fatedier e9464919d1 protocol: add v2 wire protocol with binary framing and capability negotiation (#5294) 2026-04-27 00:17:00 +08:00
fatedier e8dfd6efcc web/frpc: use static imports for proxy and visitor route components (#5286) 2026-04-14 01:18:31 +08:00
fatedier a9a4416ecf vhost/http: fix auth bypass when routeByHTTPUser is used with proxy-style requests (#5285) 2026-04-14 00:58:19 +08:00
fatedier d667be7a0a update architecture pic (#5270) 2026-03-30 03:22:35 +08:00
fatedier 31c3deb4f7 deps: bump golib to v0.6.0 (#5269) 2026-03-30 00:29:17 +08:00
fatedier 31e271939b test/e2e: allocate dynamic ports outside whitelist ranges in server whitelist test (#5268) 2026-03-30 00:21:30 +08:00
fatedier 061c141756 update README.md (#5267) 2026-03-29 23:53:17 +08:00