Skip to content

docs(proposal): add what/why connection rate limiting proposal - #962

Open
abdallahsamabd wants to merge 1 commit into
praxis-proxy:mainfrom
abdallahsamabd:proposal/123
Open

docs(proposal): add what/why connection rate limiting proposal#962
abdallahsamabd wants to merge 1 commit into
praxis-proxy:mainfrom
abdallahsamabd:proposal/123

Conversation

@abdallahsamabd

@abdallahsamabd abdallahsamabd commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds the What/Why proposal for connection rate limiting (per-source-IP concurrent connection limits, new connection rate limits, and configurable rejection behavior) at the listener layer.

Which issue(s) does this relate to?

Part of #123

Checklist

  • Signed off all commits (git commit -s)
  • Tests added or updated
  • Documentation updated (if applicable)
  • make lint && make test passes locally

Does this introduce a breaking change?

No. Documentation-only change.

@abdallahsamabd
abdallahsamabd requested a review from a team August 12, 2026 09:19
@abdallahsamabd abdallahsamabd changed the title docs(proposal): add connection rate limiting proposal docs(proposal): add what/why connection rate limiting proposal Aug 12, 2026

@praxis-bot praxis-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Proposal Review: Connection Rate Limiting (What/Why)

The proposal is well-structured and clearly motivates the need for per-source-IP connection-level limiting. The threat model, competitive landscape, and user stories are strong. Three issues to address before merging.

Issues: 1 Large, 2 Medium

HTTP parsing or TLS handshake, so malicious clients
are rejected as cheaply as possible.
- Integrate with the existing metrics pipeline to
expose connection-limit rejections as Prometheus

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Large] The goal to "operate at the connection (L4) layer, before any HTTP parsing or TLS handshake" contradicts the HTTP 429 rejection behavior listed in the What section (line 42). Sending an HTTP 429 requires completing the TLS handshake on HTTPS listeners and writing an HTTP-framed response, which is not possible at raw L4.

Please reconcile: either (a) clarify that the 429 option only applies after TLS/HTTP framing is established (making the "before any parsing" claim apply only to RST and silent-drop modes), or (b) remove 429 from the rejection behaviors and note it as a non-goal for the L4 layer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Valid. The 429 mode requires TLS + HTTP framing to be established, so it cannot operate at raw L4. Updated the goals to clarify: RST and silent-drop apply pre-handshake; 429 is only available for connections that have completed TLS/HTTP negotiation. The "before any parsing" claim now scopes to RST/drop modes only

is no mechanism to limit the rate or count of
connections from a single source IP. This means a
single client can exhaust the listener's connection
pool, starving other clients.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Medium] "connection pool" is incorrect terminology for the listener side. In Praxis (and proxies generally), connection pools are outbound upstream constructs. The listener has a connection ceiling (max_connections). The same incorrect usage appears in the user story on line 128.

Please change both occurrences of "connection pool" to "connection capacity" or "connection slots" to match the codebase terminology.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct — "connection pool" is an upstream concept. Changed to "connection capacity" in both occurrences


Add per-source-IP connection-level rate limiting to
Praxis listeners, independent of the existing
request-level rate limiter.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Medium] The proposal does not acknowledge that at L4 (pre-HTTP), the source IP is the raw TCP peer address. Behind a reverse proxy, load balancer, or NAT gateway, all downstream clients share one peer IP. Unlike the request-level rate limiter, which can inspect X-Forwarded-For headers, an L4 connection limiter cannot distinguish individual clients behind shared addresses. This is a significant operational limitation that affects real-world deployments.

Please add a bullet to Non-goals (or a note in the What section) acknowledging this limitation, e.g.: "PROXY protocol or X-Forwarded-For-based client identification -- at L4 the source IP is the TCP peer address; deployments behind NAT or load balancers should account for shared IPs when setting thresholds."

@abdallahsamabd abdallahsamabd Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Acknowledged. Added a Non-goals bullet noting that at L4 the source IP is the raw TCP peer address — deployments behind NAT or load balancers share one peer IP and should set thresholds accordingly. Unlike the L7 rate limiter (which could be extended to inspect X-Forwarded-For or similar headers), the L4 limiter has no path to real-client identification without PROXY protocol support, which is out of scope for this proposal

Signed-off-by: Abdallah Samara <abdallahsamabd@gmail.com>
@abdallahsamabd

Copy link
Copy Markdown
Contributor Author

Hi @shaneutt
The L4 connection limiter will use the raw TCP peer address — clients behind NAT/LB share one IP and cannot be distinguished (no headers exist at accept time). This is a permanent architectural constraint at L4, unlike the L7 rate limiter which could potentially be extended to inspect X-Forwarded-For.

Should we treat PROXY protocol support as a prerequisite for this feature, or is it acceptable to ship with the raw peer IP limitation and add PROXY protocol as a follow-up? If the latter, should we open a separate issue for PROXY protocol listener support?

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