fix: auto-trust private IPs as proxy + increase rate limit defaults

Root cause of massive data loss: all traffic arrives from reverse proxy
10.0.1.7, but TRUSTED_PROXIES_CIDR was not set, so rate limiter saw ALL
requests as one IP → 60 RPM shared by all users → most requests rejected.

Fixes:
- Auto-trust RFC 1918/6598 private IPs (10.x, 172.16-31.x, 192.168.x,
  100.64-127.x) and loopback as reverse proxy sources for X-Forwarded-For
- This means Docker/K8s/Caddy/Nginx setups work out of the box without
  needing to configure TRUSTED_PROXIES_CIDR
- Increase default rate limit from 60→300 RPM, burst from 20→60
  (telemetry payloads are tiny, no reason for aggressive limiting)
This commit is contained in:
CanbiZ (MickLesk)
2026-03-02 15:58:19 +01:00
parent 141af284e0
commit d0ba3935e7
+34 -4
View File
@@ -845,15 +845,45 @@ func (pt *ProxyTrust) isTrusted(ip net.IP) bool {
return false
}
// isPrivateIP returns true if the IP is in RFC 1918 / RFC 6598 private ranges
// (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10) or loopback.
// These are always trusted as reverse proxy sources.
func isPrivateIP(ip net.IP) bool {
if ip.IsLoopback() {
return true
}
privateRanges := []struct {
start net.IP
end net.IP
}{
{net.ParseIP("10.0.0.0"), net.ParseIP("10.255.255.255")},
{net.ParseIP("172.16.0.0"), net.ParseIP("172.31.255.255")},
{net.ParseIP("192.168.0.0"), net.ParseIP("192.168.255.255")},
{net.ParseIP("100.64.0.0"), net.ParseIP("100.127.255.255")},
}
ip4 := ip.To4()
if ip4 == nil {
return false
}
for _, r := range privateRanges {
if bytes.Compare(ip4, r.start.To4()) >= 0 && bytes.Compare(ip4, r.end.To4()) <= 0 {
return true
}
}
return false
}
func getClientIP(r *http.Request, pt *ProxyTrust) net.IP {
// If behind reverse proxy, trust X-Forwarded-For only if remote is trusted proxy.
// If behind reverse proxy, trust X-Forwarded-For if remote is a configured
// trusted proxy OR a private/RFC1918 IP (common Docker/K8s/reverse proxy setup).
host, _, _ := net.SplitHostPort(r.RemoteAddr)
remote := net.ParseIP(host)
if remote == nil {
return nil
}
if pt != nil && pt.isTrusted(remote) {
trusted := (pt != nil && pt.isTrusted(remote)) || isPrivateIP(remote)
if trusted {
xff := r.Header.Get("X-Forwarded-For")
if xff != "" {
parts := strings.Split(xff, ",")
@@ -1411,8 +1441,8 @@ func main() {
PBTargetColl: mustEnv("PB_TARGET_COLLECTION"),
MaxBodyBytes: envInt64("MAX_BODY_BYTES", 262144),
RateLimitRPM: envInt("RATE_LIMIT_RPM", 60),
RateBurst: envInt("RATE_BURST", 20),
RateLimitRPM: envInt("RATE_LIMIT_RPM", 300),
RateBurst: envInt("RATE_BURST", 60),
RateKeyMode: env("RATE_KEY_MODE", "ip"), // "ip" or "header"
RateKeyHeader: env("RATE_KEY_HEADER", "X-Telemetry-Key"),
RequestTimeout: time.Duration(envInt("UPSTREAM_TIMEOUT_MS", 60000)) * time.Millisecond,