FEATURE: global rate limiter can bypass local IPs
This commit is contained in:
parent
e3f8182125
commit
cecd7d0d07
|
@ -178,5 +178,8 @@ max_admin_api_reqs_per_key_per_minute = 60
|
|||
|
||||
max_requests_per_ip_per_minute = 200
|
||||
max_requests_per_ip_per_10_seconds = 50
|
||||
# global rate limiter will simply warn if the limit is exceeded, can be warn, block or none
|
||||
# global rate limiter will simply warn if the limit is exceeded, can be warn+block, warn, block or none
|
||||
max_requests_per_ip_mode = none
|
||||
|
||||
# bypass rate limiting any IP resolved as a private IP
|
||||
max_requests_rate_limit_on_private = false
|
||||
|
|
|
@ -142,14 +142,27 @@ class Middleware::RequestTracker
|
|||
log_request_info(env, result, info) unless env["discourse.request_tracker.skip"]
|
||||
end
|
||||
|
||||
PRIVATE_IP = /^(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD])/
|
||||
|
||||
def is_private_ip?(ip)
|
||||
ip = IPAddr.new(ip) rescue nil
|
||||
!!(ip && ip.to_s.match?(PRIVATE_IP))
|
||||
end
|
||||
|
||||
def rate_limit(env)
|
||||
|
||||
if (
|
||||
GlobalSetting.max_requests_per_ip_mode == "block" ||
|
||||
GlobalSetting.max_requests_per_ip_mode == "warn"
|
||||
GlobalSetting.max_requests_per_ip_mode == "warn" ||
|
||||
GlobalSetting.max_requests_per_ip_mode == "warn+block"
|
||||
)
|
||||
|
||||
ip = Rack::Request.new(env).ip
|
||||
|
||||
if !GlobalSetting.max_requests_rate_limit_on_private
|
||||
return false if is_private_ip?(ip)
|
||||
end
|
||||
|
||||
limiter10 = RateLimiter.new(
|
||||
nil,
|
||||
"global_ip_limit_10_#{ip}",
|
||||
|
@ -172,9 +185,12 @@ class Middleware::RequestTracker
|
|||
type = 60
|
||||
limiter60.performed!
|
||||
rescue RateLimiter::LimitExceeded
|
||||
if GlobalSetting.max_requests_per_ip_mode == "warn"
|
||||
if (
|
||||
GlobalSetting.max_requests_per_ip_mode == "warn" ||
|
||||
GlobalSetting.max_requests_per_ip_mode == "warn+block"
|
||||
)
|
||||
Rails.logger.warn("Global IP rate limit exceeded for #{ip}: #{type} second rate limit, uri: #{env["REQUEST_URI"]}")
|
||||
false
|
||||
!(GlobalSetting.max_requests_per_ip_mode == "warn")
|
||||
else
|
||||
true
|
||||
end
|
||||
|
|
|
@ -112,6 +112,45 @@ describe Middleware::RequestTracker do
|
|||
expect(status).to eq(200)
|
||||
end
|
||||
|
||||
it "blocks private IPs if not skipped" do
|
||||
global_setting :max_requests_per_ip_per_10_seconds, 1
|
||||
global_setting :max_requests_per_ip_mode, 'warn+block'
|
||||
global_setting :max_requests_rate_limit_on_private, true
|
||||
|
||||
env1 = env("REMOTE_ADDR" => "127.0.0.2")
|
||||
|
||||
status, _ = middleware.call(env1)
|
||||
status, _ = middleware.call(env1)
|
||||
|
||||
expect(Rails.logger.warnings).to eq(1)
|
||||
expect(status).to eq(429)
|
||||
end
|
||||
|
||||
it "does nothing for private IPs if skipped" do
|
||||
global_setting :max_requests_per_ip_per_10_seconds, 1
|
||||
global_setting :max_requests_per_ip_mode, 'warn+block'
|
||||
global_setting :max_requests_rate_limit_on_private, false
|
||||
|
||||
env1 = env("REMOTE_ADDR" => "127.0.3.1")
|
||||
|
||||
status, _ = middleware.call(env1)
|
||||
status, _ = middleware.call(env1)
|
||||
|
||||
expect(Rails.logger.warnings).to eq(0)
|
||||
expect(status).to eq(200)
|
||||
end
|
||||
|
||||
it "does warn if rate limiter is enabled via warn+block" do
|
||||
global_setting :max_requests_per_ip_per_10_seconds, 1
|
||||
global_setting :max_requests_per_ip_mode, 'warn+block'
|
||||
|
||||
status, _ = middleware.call(env)
|
||||
status, _ = middleware.call(env)
|
||||
|
||||
expect(Rails.logger.warnings).to eq(1)
|
||||
expect(status).to eq(429)
|
||||
end
|
||||
|
||||
it "does warn if rate limiter is enabled" do
|
||||
global_setting :max_requests_per_ip_per_10_seconds, 1
|
||||
global_setting :max_requests_per_ip_mode, 'warn'
|
||||
|
|
Loading…
Reference in New Issue