github: shadowy octopus with the head of a robot, emblazoned with the Dreamwidth swirl (Default)
github ([personal profile] github) wrote in [site community profile] changelog2026-05-24 02:45 pm

[dreamwidth/dreamwidth] cccfbb: Exclude internal/private IPs from request rate lim...

Branch: refs/heads/main Home: https://github.com/dreamwidth/dreamwidth Commit: cccfbb533dff822df6cccd13d821e7683a978c53 https://github.com/dreamwidth/dreamwidth/commit/cccfbb533dff822df6cccd13d821e7683a978c53 Author: Mark Smith mark@dreamwidth.org Date: 2026-05-24 (Sun, 24 May 2026)

Changed paths: M cgi-bin/DW/RateLimit.pm M cgi-bin/Plack/Middleware/DW/RateLimit.pm M etc/config.pl.example M t/rate-limit.t

Log Message:


Exclude internal/private IPs from request rate limiting (#3547)

Load-balancer health checks (GET / from the ALB) were getting 429ed: they arrive without a trusted X-Forwarded-For, so LJ::get_remote_ip() resolves to the ALB's private VPC IP, and every web task's checks collapse onto one shared-memcache IP bucket, blowing past the 30 req/60s anonymous limit.

Add DW::RateLimit->ip_is_excluded($ip), which returns true for RFC1918 + loopback addresses (memoized Net::Subnet matcher), or for whatever an optional $LJ::RATE_LIMIT_EXCLUDE_IP coderef/subnet_matcher says when set. The Plack rate-limit middleware now early-returns for excluded IPs before any bucket check, for both anonymous and authenticated requests.

Real external traffic still carries a trusted XFF, so its resolved IP is the public client IP and stays limited; only intra-VPC infrastructure (resolved to a private IP) is skipped. Link-local 169.254/16 is intentionally not exempt.

Document $RATE_LIMIT_EXCLUDE_IP in etc/config.pl.example and add unit coverage in t/rate-limit.t (ranges, boundaries, override, undef/empty).

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com