# HG changeset patch # User Emmanuel Gil Peyrot # Date 1625856880 -7200 # Node ID b935276ab1b4edf9de0842c68d39b7f31fe732d4 # Parent 306066898e5fa4b1e4f756df481f19a91fb16e08 mod_limits: Obsolete this module, it is included in Prosody since 0.10 diff -r 306066898e5f -r b935276ab1b4 mod_limits/README.markdown --- a/mod_limits/README.markdown Mon Nov 22 21:01:53 2021 +0100 +++ b/mod_limits/README.markdown Fri Jul 09 20:54:40 2021 +0200 @@ -1,68 +1,8 @@ --- labels: -- 'Stage-Beta' +- 'Stage-Obsolete' summary: 'Connection-level rate limiting' +superseded_by: mod_limits ... -Introduction -============ - -On some servers, especially public ones, it is desired to make sure that -everyone gets their fair share of system resources (and no more). - -mod\_limits allows you to specify traffic bandwidth limits, preventing -any single connection hogging the server's CPU, RAM and bandwidth. - -Details -======= - -mod\_limits detects when a connection has exceeded its traffic allowance -and temporarily ignores a connection. Due to the way TCP and the OS's -network API works no data is lost, only slowed. - -Configuration -============= - -Currently mod\_limits is configured per connection type. The possible -connection types are: - -- c2s -- s2sin -- s2sout -- component - -The limits are specified like so in the **global** section of your -config (they cannot be per-host): - -``` {.lua} -limits = { - c2s = { - rate = "3kb/s"; - burst = "2s"; - }; - s2sin = { - rate = "10kb/s"; - burst = "5s"; - }; -} -``` - -All units are in terms of *bytes*, not *bits*, so that "kb/s" is -interpreted as "kilobytes per second", where a kilobyte is 1000 bytes. - -Compatibility -============= - - ----- ------------------- - 0.9 Works - 0.8 Doesn't work(\*) - ----- ------------------- - -(\*) This module can be made to work in 0.8 if you do two things: - -1. Install - [util.throttle](http://hg.prosody.im/0.9/raw-file/d46948d3018a/util/throttle.lua) - into your Prosody source's util/ directory. -2. If you use libevent apply [this - patch](http://prosody.im/patches/prosody08-mod-limits-fix.patch) to - net/server\_event.lua. +Since Prosody 0.10, this module is [included in Prosody](https://prosody.im/doc/modules/mod_limits), you will be redirected there shortly. diff -r 306066898e5f -r b935276ab1b4 mod_limits/mod_limits.lua --- a/mod_limits/mod_limits.lua Mon Nov 22 21:01:53 2021 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ --- mod_limits: Rate-limiting for Prosody --- Version: Alpha --- Author: Matthew Wild - --- Because we deal we pre-authed sessions and streams we can't be host-specific -module:set_global(); - -local filters = require "util.filters"; -local throttle = require "util.throttle"; -local timer = require "util.timer"; -local ceil = math.ceil; - -local limits_cfg = module:get_option("limits", {}); -local limits_resolution = module:get_option_number("limits_resolution", 1); - -local default_bytes_per_second = 3000; -local default_burst = 2; - -local rate_units = { b = 1, k = 3, m = 6, g = 9, t = 12 } -- Plan for the future. -local function parse_rate(rate, sess_type) - local quantity, unit, exp; - if rate then - quantity, unit = rate:match("^(%d+) ?([^/]+)/s$"); - exp = quantity and rate_units[unit:sub(1,1):lower()]; - end - if not exp then - module:log("error", "Error parsing rate for %s: %q, using default rate (%d bytes/s)", sess_type, rate, default_bytes_per_second); - return default_bytes_per_second; - end - return quantity*(10^exp); -end - -local function parse_burst(burst, sess_type) - if type(burst) == "string" then - burst = burst:match("^(%d+) ?s$"); - end - local n_burst = tonumber(burst); - if not n_burst then - module:log("error", "Unable to parse burst for %s: %q, using default burst interval (%ds)", sess_type, tostring(burst), default_burst); - end - return n_burst or default_burst; -end - --- Process config option into limits table: --- limits = { c2s = { bytes_per_second = X, burst_seconds = Y } } -local limits = {}; - -for sess_type, sess_limits in pairs(limits_cfg) do - limits[sess_type] = { - bytes_per_second = parse_rate(sess_limits.rate, sess_type); - burst_seconds = parse_burst(sess_limits.burst, sess_type); - }; -end - -local default_filter_set = {}; - -function default_filter_set.bytes_in(bytes, session) - local throttle = session.throttle; - if throttle then - local ok, balance, outstanding = throttle:poll(#bytes, true); - if not ok then - session.log("debug", "Session %q over rate limit (%d) with %d (by %d), pausing", session.full_jid or session.from_host or session.to_host, throttle.max, #bytes, outstanding); - outstanding = ceil(outstanding); - session.conn:pause(); -- Read no more data from the connection until there is no outstanding data - local outstanding_data = bytes:sub(-outstanding); - bytes = bytes:sub(1, #bytes-outstanding); - timer.add_task(limits_resolution, function () - if not session.conn then return; end - if throttle:peek(#outstanding_data) then - session.log("debug", "Resuming paused session"); - session.conn:resume(); - end - session.log("debug", "mod_limits feeding %d bytes of delayed data into stream", #outstanding_data); - -- Handle what we can of the outstanding data - session.data(outstanding_data); - end); - end - end - return bytes; -end - -local type_filters = { - c2s = default_filter_set; - s2sin = default_filter_set; - s2sout = default_filter_set; -}; - -local function filter_hook(session) - local session_type = session.type:match("^[^_]+"); - local filter_set, opts = type_filters[session_type], limits[session_type]; - if opts then - session.throttle = throttle.create(opts.bytes_per_second * opts.burst_seconds, opts.burst_seconds); - filters.add_filter(session, "bytes/in", filter_set.bytes_in, 1000); - end -end - -function module.load() - filters.add_filter_hook(filter_hook); -end - -function module.unload() - filters.remove_filter_hook(filter_hook); -end