Commit Graph

1428 Commits

Author SHA1 Message Date
fatedier
6cdef90113 web: bump dev dependencies in frpc and frps package-lock.json (#5239) 2026-03-16 23:22:42 +08:00
fatedier
85e8e2c830 web/frpc: redesign frpc dashboard with sidebar nav, proxy/visitor list and detail views (#5237) 2026-03-16 09:44:30 +08:00
fatedier
ff4ad2f907 auth/oidc: fix eager token fetch at startup, add validation and e2e tests (#5234) 2026-03-15 22:29:45 +08:00
Shani Pathak
94a631fe9c auth/oidc: cache OIDC access token and refresh before expiry (#5175)
* auth/oidc: cache OIDC access token and refresh before expiry

- Use Config.TokenSource(ctx) once at init to create a persistent
  oauth2.TokenSource that caches the token and only refreshes on expiry
- Wrap with oauth2.ReuseTokenSourceWithExpiry for configurable early refresh
- Add tokenRefreshAdvanceDuration config option (default: 300s)
- Add unit test verifying token caching with mock HTTP server

* address review comments

* auth/oidc: fallback to per-request token fetch when expires_in is missing

When an OIDC provider omits the expires_in field, oauth2.ReuseTokenSource
treats the cached token as valid forever and never refreshes it. This causes
server-side OIDC verification to fail once the JWT's exp claim passes.

Add a nonCachingTokenSource fallback: after fetching the initial token, if
its Expiry is the zero value, swap the caching TokenSource for one that
fetches a fresh token on every request, preserving the old behavior for
providers that don't return expires_in.

* auth/oidc: fix gosec lint and add test for zero-expiry fallback

Suppress G101 false positive on test-only dummy token responses.
Add test to verify per-request token fetch when expires_in is missing.
Update caching test to account for eager initial token fetch.

* fix lint
2026-03-12 00:24:46 +08:00
fatedier
6b1be922e1 add AGENTS.md and CLAUDE.md, remove them from .gitignore (#5232) 2026-03-12 00:21:31 +08:00
fatedier
4f584f81d0 test/e2e: replace sleeps with event-driven waits in chaos/group/store tests (#5231)
* test/e2e: replace sleeps with event-driven waits in chaos/group/store tests

Replace 21 time.Sleep calls with deterministic waiting using
WaitForOutput, WaitForTCPReady, and a new WaitForTCPUnreachable helper.
Add CountOutput method for snapshot-based incremental log matching.

* test/e2e: validate interval and cap dial/sleep to remaining deadline in WaitForTCPUnreachable
2026-03-12 00:11:09 +08:00
fatedier
9669e1ca0c test/e2e: replace RunProcesses client sleep with log-based proxy readiness detection (#5226)
* test/e2e: replace RunProcesses client sleep with log-based proxy readiness detection

Replace the fixed 1500ms sleep in RunProcesses with event-driven proxy
registration detection by monitoring frpc log output for "start proxy
success" messages.

Key changes:
- Add thread-safe SafeBuffer to replace bytes.Buffer in Process, enabling
  concurrent read/write of process output during execution
- Add Process.WaitForOutput() to poll process output for pattern matches
  with timeout and early exit on process termination
- Add waitForClientProxyReady() that uses config.LoadClientConfig() to
  extract proxy names, then waits for each proxy's success log
- For visitor-only clients (no deterministic readiness signal), fall back
  to the original sleep with elapsed time deducted

* test/e2e: use shared deadline for proxy readiness and fix doc comment

- Use a single deadline in waitForClientProxyReady so total wait across
  all proxies does not exceed the given timeout
- Fix WaitForOutput doc comment to accurately describe single pattern
  with count semantics
2026-03-09 22:28:23 +08:00
fatedier
48e8901466 test/e2e: optimize RunFrps/RunFrpc with process exit detection (#5225)
* test/e2e: optimize RunFrps/RunFrpc with process exit detection

Refactor Process to track subprocess lifecycle via a done channel,
replacing direct cmd.Wait() in Stop() to avoid double-Wait races.
RunFrps/RunFrpc now use select on the done channel instead of fixed
sleeps, allowing short-lived processes (verify, startup failures) to
return immediately while preserving existing timeout behavior for
long-running daemons.

* test/e2e: guard Process against double-Start and Stop-before-Start

Add started flag to prevent double-Start panics and allow Stop to
return immediately when the process was never started. Use sync.Once
for closing the done channel as defense-in-depth against double close.
2026-03-09 10:28:47 +08:00
fatedier
bcd2424c24 test/e2e: optimize e2e test time by replacing sleeps with TCP readiness checks (#5223)
Replace the fixed 500ms sleep after each frps startup in RunProcesses
with a TCP dial-based readiness check that polls the server bind port.
This reduces the e2e suite wall time from ~97s to ~43s.

Also simplify the RunProcesses API to accept a single server template
string instead of a slice, matching how every call site uses it.
2026-03-08 23:41:33 +08:00
fatedier
c7ac12ea0f server/group: refactor with shared abstractions and fix concurrency issues (#5222)
* server/group: refactor group package with shared abstractions and fix concurrency issues

Extract common patterns into reusable components:
- groupRegistry[G]: generic concurrent map for group lifecycle management
- baseGroup: shared plumbing for listener-based groups (TCP, HTTPS, TCPMux)
- Listener: unified virtual listener replacing 3 identical implementations

Fix concurrency issues:
- Stale-pointer race: isCurrent check + errGroupStale + controller retry loops
- Worker generation safety: pass realLn and acceptCh as params instead of reading mutable fields
- Connection leak: close conn on worker panic recovery path
- ABBA deadlock in HTTP UnRegister: consistent lock ordering (group.mu -> registry.mu)
- Round-robin overflow in HTTPGroup: use unsigned modulo

Add unit tests (17 tests) for registry, listener, and baseGroup.
Add TCPMux group load balancing e2e test.

* server/group: replace tautological assertion with require.NotPanics

* server/group: remove blank line between doc comment and type declaration
2026-03-08 18:57:21 +08:00
fatedier
eeb0dacfc1 pkg/metrics/mem: remove redundant map write-backs and optimize proxy lookup (#5221)
Remove 4 redundant pointer map write-backs in OpenConnection,
CloseConnection, AddTrafficIn, and AddTrafficOut since the map stores
pointers and mutations are already visible without reassignment.

Optimize GetProxiesByTypeAndName from O(n) full map scan to O(1) direct
map lookup by proxy name.
2026-03-08 10:40:39 +08:00
Oleksandr Redko
535eb3db35 refactor: use maps.Clone and slices.Concat (#5220) 2026-03-08 10:38:16 +08:00
fatedier
605f3bdece client/visitor: deduplicate visitor connection handshake and wrapping (#5219)
Extract two shared helpers to eliminate duplicated code across STCP,
SUDP, and XTCP visitors:

- dialRawVisitorConn: handles ConnectServer + NewVisitorConn handshake
  (auth, sign key, 10s read deadline, error check)
- wrapVisitorConn: handles encryption + pooled compression wrapping,
  returning a recycleFn for pool resource cleanup

SUDP is upgraded from WithCompression to WithCompressionFromPool,
aligning with the pooled compression used by STCP and XTCP.
2026-03-08 01:03:40 +08:00
fatedier
764a626b6e server/control: deduplicate close-proxy logic and UserInfo construction (#5218)
Extract closeProxy() helper to eliminate duplicated 4-step cleanup
sequence (Close, PxyManager.Del, metrics, plugin notify) between
worker() and CloseProxy().

Extract loginUserInfo() helper to eliminate 4 repeated plugin.UserInfo
constructions using LoginMsg fields.

Optimize worker() to snapshot and clear the proxies map under lock,
then perform cleanup outside the lock to reduce lock hold time.
2026-03-08 00:02:14 +08:00
Oleksandr Redko
c2454e7114 refactor: fix modernize lint issues (#5215) 2026-03-07 23:10:19 +08:00
fatedier
017d71717f server: introduce SessionContext to encapsulate NewControl parameters (#5217)
Replace 10 positional parameters in NewControl() with a single
SessionContext struct, matching the client-side pattern. This also
eliminates the post-construction mutation of clientRegistry and
removes two TODO comments.
2026-03-07 20:17:00 +08:00
Oleksandr Redko
bd200b1a3b fix: typos in comments, tests, functions (#5216) 2026-03-07 18:43:04 +08:00
fatedier
c70ceff370 fix: three high-severity bugs across nathole, proxy, and udp modules (#5214)
- pkg/nathole: add RLock when reading clientCfgs map in PreCheck path
  to prevent concurrent map read/write crash
- server/proxy: fix error variable shadowing in GetWorkConnFromPool
  that could return a closed connection with nil error
- pkg/util/net: check ListenUDP error before spawning goroutines
  and assign readConn to struct field so Close() works correctly
2026-03-07 13:36:02 +08:00
fatedier
bb3d0e7140 deduplicate common logic across proxy, visitor, and metrics modules (#5213)
- Replace duplicate parseBasicAuth with existing httppkg.ParseBasicAuth
- Extract buildDomains helper in BaseProxy for HTTP/HTTPS/TCPMux proxies
- Extract toProxyStats helper to deduplicate ProxyStats construction
- Extract startVisitorListener helper in BaseProxy for STCP/SUDP proxies
- Extract acceptLoop helper in BaseVisitor for STCP/XTCP visitors
2026-03-07 12:00:27 +08:00
fatedier
cf396563f8 client/proxy: unify work conn wrapping across all proxy types (#5212)
* client/proxy: extract wrapWorkConn to deduplicate UDP/SUDP connection wrapping

Move the repeated rate-limiting, encryption, and compression wrapping
logic from UDPProxy and SUDPProxy into a shared BaseProxy.wrapWorkConn
method, reducing ~18 lines of duplication in each proxy type.

* client/proxy: unify work conn wrapping with pooled compression for all proxy types

Refactor wrapWorkConn to accept encKey parameter and return
(io.ReadWriteCloser, recycleFn, error), enabling HandleTCPWorkConnection
to reuse the same limiter/encryption/compression pipeline.

Switch all proxy types from WithCompression to WithCompressionFromPool.
TCP non-plugin path calls recycleFn via defer after Join; plugin and
UDP/SUDP paths skip recycle (objects are GC'd safely, per golib contract).
2026-03-07 01:33:37 +08:00
fatedier
0b4f83cd04 pkg/config: use modern Go stdlib for sorting and string operations (#5210)
- slices.SortedFunc + maps.Values + cmp.Compare instead of manual
  map-to-slice collection + sort.Slice (source/aggregator.go)
- strings.CutSuffix instead of HasSuffix+TrimSuffix, and deduplicate
  error handling in BandwidthQuantity.UnmarshalString (types/types.go)
2026-03-06 23:13:29 +08:00
fatedier
e9f7a1a9f2 pkg: use modern Go stdlib functions to simplify code (#5209)
- strings.CutPrefix instead of HasPrefix+TrimPrefix (naming, legacy)
- slices.Contains instead of manual loop (plugin/server)
- min/max builtins instead of manual comparisons (nathole)
2026-03-06 22:14:46 +08:00
fatedier
d644593342 server/proxy: simplify HTTPS and TCPMux proxy domain registration (#5208)
Consolidate the separate custom-domain loop and subdomain block into a
single unified loop, matching the pattern already applied to HTTPProxy
in PR #5207. No behavioral change.
2026-03-06 21:31:29 +08:00
fatedier
427c4ca3ae server/proxy: simplify HTTP proxy domain registration by removing duplicate loop (#5207)
The Run() method had two nearly identical loop blocks for registering
custom domains and subdomain, with the same group/non-group registration
logic copy-pasted (~30 lines of duplication).

Consolidate by collecting all domains into a single slice first, then
iterating once with the shared registration logic. Also fixes a minor
inconsistency where the custom domain block used routeConfig.Domain in
CanonicalAddr but the subdomain block used tmpRouteConfig.Domain.
2026-03-06 21:17:30 +08:00
fatedier
f2d1f3739a pkg/util/xlog: fix AddPrefix not updating existing prefix due to range value copy (#5206)
In AddPrefix, the loop `for _, p := range l.prefixes` creates a copy
of each element. Assignments to p.Value and p.Priority only modify
the local copy, not the original slice element, causing updates to
existing prefixes to be silently lost.

This affects client/service.go where AddPrefix is called with
Name:"runID" on reconnection — the old runID value would persist
in log output instead of being updated to the new one.

Fix by using index-based access `l.prefixes[i]` to modify the
original slice element, and add break since prefix names are unique.
2026-03-06 20:44:40 +08:00
fatedier
c23894f156 fix: validate CA cert parsing and add missing ReadHeaderTimeout (#5205)
- pkg/transport/tls.go: check AppendCertsFromPEM return value and
  return clear error when CA file contains no valid PEM certificates
- pkg/plugin/client/http2http.go: set ReadHeaderTimeout to 60s to
  match other plugins and prevent slow header attacks
- pkg/plugin/client/http2https.go: same ReadHeaderTimeout fix
2026-03-06 17:59:41 +08:00
fatedier
cb459b02b6 fix: WebsocketListener nil panic and OIDC auth data race (#5204)
- pkg/util/net/websocket.go: store ln parameter in struct to prevent
  nil pointer panic when Addr() is called
- pkg/auth/oidc.go: replace unsynchronized []string with map + RWMutex
  for subjectsFromLogin to fix data race across concurrent connections
2026-03-06 16:51:52 +08:00
fatedier
8f633fe363 fix: return buffers to pool on error paths to reduce GC pressure (#5203)
- pkg/nathole/nathole.go: add pool.PutBuf(buf) on ReadFromUDP error
  and DecodeMessageInto error paths in waitDetectMessage
- pkg/proto/udp/udp.go: add defer pool.PutBuf(buf) in writerFn to
  ensure buffer is returned when the goroutine exits
2026-03-06 15:55:22 +08:00
fatedier
c62a1da161 fix: close connections on error paths to prevent resource leaks (#5202)
Fix connection leaks in multiple error paths across client and server:
- server/proxy/http: close tmpConn when WithEncryption fails
- client/proxy: close localConn when ProxyProtocol WriteTo fails
- client/visitor/sudp: close visitorConn on all error paths in getNewVisitorConn
- client/visitor/xtcp: close tunnelConn when WithEncryption fails
- client/visitor/xtcp: close lConn when NewKCPConnFromUDP fails
- pkg/plugin/client/unix_domain_socket: close localConn and connInfo.Conn when WriteTo fails, close connInfo.Conn when DialUnix fails
- pkg/plugin/client/tls2raw: close tlsConn when Handshake or Dial fails
2026-03-06 15:18:38 +08:00
fatedier
f22f7d539c server/group: fix port leak and incorrect Listen port in TCPGroup (#5200)
Fix two bugs in TCPGroup.Listen():
- Release acquired port when net.Listen fails to prevent port leak
- Use realPort instead of port for net.Listen to ensure consistency
  between port manager records and actual listening port
2026-03-06 02:25:47 +08:00
fatedier
462c987f6d pkg/msg: change UDPPacket.Content from string to []byte to avoid redundant base64 encode/decode (#5198) 2026-03-06 01:38:24 +08:00
fatedier
541878af4d docs: update release notes for config parsing error improvements (#5196) 2026-03-05 00:00:46 +08:00
fatedier
b7435967b0 pkg/config: fix line numbers shown incorrectly for TOML type mismatch errors (#5195) 2026-03-04 20:53:22 +08:00
fatedier
774478d071 pkg/config: improve error messages with line number details for config parsing (#5194)
When frpc verify encounters config errors, the error messages now include
line/column information to help users locate problems:

- TOML syntax errors: report line and column from the TOML parser
  (e.g., "toml: line 4, column 11: expected character ]")
- Type mismatch errors: report the field name and approximate line number
  (e.g., "line 3: field \"proxies\": cannot unmarshal string into ...")
- File format detection: use file extension to determine format, preventing
  silent fallthrough from TOML to YAML parser which produced confusing errors

Previously, a TOML file with syntax errors would silently fall through to the
YAML parser, which would misinterpret the content and produce unhelpful errors
like "json: cannot unmarshal string into Go value of type v1.ClientConfig".

https://claude.ai/code/session_017HWLfcXS3U2hLoy4dsg8Nv

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-04 19:27:30 +08:00
fatedier
fbeb6ca43a refactor: restructure API packages into client/http and server/http with typed proxy/visitor models (#5193) 2026-03-04 17:38:43 +08:00
fatedier
381245a439 build: add noweb tag to allow building without frontend assets (#5189) 2026-03-02 01:32:19 +08:00
fatedier
01997deb98 add persistent proxy/visitor store with CRUD API and web UI (#5188) 2026-03-02 01:09:59 +08:00
fatedier
d0347325fc pkg/config: fix custom domain validation to prevent false matches with subdomain host (#5178) 2026-02-13 14:10:18 +08:00
fatedier
519368b1fd server/api: fix DeleteProxies endpoint returning empty response instead of JSON (#5163) 2026-02-06 11:22:34 +08:00
fatedier
9634fd99d1 web: ensure npm install runs before build (#5154) 2026-02-04 12:55:24 +08:00
fatedier
7a1c248b67 bump version to 0.67.0 (#5146) 2026-01-31 13:49:29 +08:00
fatedier
886c9c2fdb web/frpc: redesign dashboard (#5145) 2026-01-31 12:43:31 +08:00
fatedier
266c492b5d web/frps: add detailed client and proxy views with enhanced tracking (#5144) 2026-01-31 02:18:35 +08:00
fatedier
5dd70ace6b refactor: move web embeds to web/ directory (#5139) 2026-01-27 02:56:57 +08:00
fatedier
fb2c98e87b rotate gold sponsor 2026-01-27 02:45:57 +08:00
fatedier
ed13141c56 refactor: separate API handlers into dedicated packages with improved HTTP utilities (#5127) 2026-01-14 19:50:55 +08:00
fatedier
3370bd53f5 udp: fix proxy protocol header sent on every packet instead of first packet only (#5119) 2026-01-09 11:33:00 +08:00
fatedier
1245f8804e server: replace client metadata with IP address in registry (#5118) 2026-01-09 11:07:19 +08:00
fatedier
479e9f50c2 web/frpc: refactor dashboard with improved structure and API layer (#5117) 2026-01-09 00:40:51 +08:00
fatedier
a4175a2595 update release notes (#5116) 2026-01-08 20:25:03 +08:00