Monitoring WebSocket connections have no limit and can exhaust resources #3315
Closed
rustytrees
started this conversation in
Potential issues
Replies: 1 comment
|
I can run Swival /audit, too. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
What is happening?
The monitoring UI accepts WebSocket connections without a connection limit. Each accepted connection is stored in a process-wide map and receives a dedicated read goroutine. An authenticated client, or any client when monitoring authentication is disabled, can repeatedly open
/api/wsconnections and grow the number of live sockets and goroutines until idle deadlines expire. Connections kept active with Pong frames can remain registered indefinitely.There is also a broadcast amplification path: each metrics update walks every registered connection while holding global client and write locks, and writes to the clients sequentially with a five-second deadline per client. Slow clients can therefore delay all WebSocket writes, with worst-case delay proportional to the number of connections.
Relevant code
The client registry is an unbounded map; the monitoring configuration has no maximum-WebSocket-clients field:
MonitoringUI.clientsand locks, lines 120-137MonitoringUIConfig, lines 23-37Every successful upgrade is registered without checking a count and then starts a goroutine:
The 120-second read deadline limits completely idle connections, but Pong frames extend it without limiting connection age or count:
Broadcasting holds global locks and performs sequential writes with a per-client deadline:
The general DNS
max_clientslimit does not cover this HTTP/WebSocket server; it is enforced in the UDP/TCP DNS listeners instead:max_clientsenforcement, lines 455-500Exposure and impact
The monitoring UI is disabled and loopback-bound by default, which substantially limits the default exposure. The issue matters when an administrator enables the UI and makes it reachable by other hosts, uses a reverse proxy, disables authentication, or when authenticated-but-untrusted clients exist. Basic authentication restricts who can reach the handler, but does not impose a resource quota on an authenticated client.
Potential effects include growing socket/file-descriptor and goroutine usage, increased memory and CPU consumption, and WebSocket update stalls caused by slow-client writes. At sufficient scale this may degrade or terminate the dnscrypt-proxy process, affecting DNS service.
How to reproduce
/api/wswithout closing the connections.ui.clientsand each retains a goroutine; there is no rejection threshold.Expected behavior / possible fix
This is distinct from discussion #2901, which concerned concurrent WebSocket writes and was addressed in 2.1.13. The current concern is the absence of resource limits and the linear, globally serialized broadcast path.
All reactions