Implement tunnel limiting in smokescreen #284
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR does the following:
NOTE: This allows as many CONNECT requests to call smokescreen, perform ACL checks etc, but only the tunnel limit number of connections can actually call
DialContext()and establish tunnel. If we want to limit pre-Dial access also, we can configure the rate-limiter and concurrency-limiter for that purpose.Motivation
The
max_concurrent_requestsconfiguration in Smokescreen is ineffective for CONNECT tunnels. The rate limiter acquires a slot when ServeHTTP() starts and releases it via defer when the function returns. For CONNECT requests, goproxy hijacks the connection and ServeHTTP() returns immediately while the tunnel continues in background goroutines. This allows unlimited CONNECT tunnels regardless of the configured limit, enabling resource exhaustion (OOM crash in ~10 seconds with 64MB memory limit).The current
max_concurrent_requestsis basically limiting the number of connections being served by smokescreen, but does not monitor if they still last. We need a dedicated tunnel limiter for that.Test plan
We create 20 non-CONNECT requests and then 20 CONNECT requests to a slow backend via smokescreen proxy. The first 20 requests get handled by the existing concurrency limiter in smokescreen. The tunnel limiting restricts the number of CONNECT requests.
Before
We see the number of connections exceeding the
max_concurrent_requestslimit and blocking smokescreen resources for 5 seconds.Screen.Recording.2026-02-12.at.2.30.17.PM.mov
After
We see the tunnel limit is applied and allows only 3 requests. 17 other CONNECT requests are rejected
Screen.Recording.2026-02-12.at.2.32.03.PM.mov