# -*- text -*-
#
#  $Id: 8969adf3433a639688137349f26aa7cf479063fb $

#
#  This module performs rate limiting on proxied packets.
#
#  In some cases, a home server does not delay Access-Reject packets.
#  Badly behaved end-user devices may then try to authenticate many
#  hundreds of times a second.  This behavior is effectively a denial
#  of service (DoS) attack on the RADIUS infastructure.
#
#  This module tracks Access-Reject packets based on a key.  If the
#  device is trying to authenticate too many times in quick
#  succession, the module will return a reject rather than proxying
#  the packet.  These Access-Requests will not be proxied for a
#  configurable period of time, which is the "suppression period".
#
#  Access-Reject responses from home servers for proxied requests are
#  store in a local tracking structure, keyed by username + supplicant
#  MAC. IDs are tracked to identify retransmission of the most recent
#  request.  There should be few issues with lock contention, as the
#  tracking structure is designed carefully to avoid locks, or use
#  multiple distinct locks.
#
#  Prior to proxying a request (in the pre-proxy section), the
#  tracking structure is queried. If an activate entry exists for the
#  device, then an Access-Reject will be sent and proxying will be
#  cancelled. Multiple requests arriving within the same second from a
#  device will cause the suppression period to the extended.
#
#  When a request is proxied, if the reponse from the home server (in
#  the post-proxy section) is Access-Reject, then the device will be
#  added to the corresponding tracking table.  If the device does not
#  quickly re-authenticate, then the tracking tavble entry is
#  discarded.
#
#  However, if multiple requests arrive for the same device within the
#  same second, the module start rate-limiting requests as described
#  above.
#

#
#  Update the "authorize" section to list the "proxy_rate_limit" module:
#
#	authorize {
#		...
#		proxy_rate_limit
#		...
#	}
#
#  This allows the bad packets to be rejected as quickly as possible.
#
#  If you want the bad packets to be discarded instead, you can do:
#
#	authorize {
#		...
#		proxy_rate_limit {
#			reject = 1   # don't stop processing on reject
#		}
#		if (reject) {
#			do_not_respond
#		}
#		...
#	}
#
#
#  And update the "post-proxy" section to list the "proxy_rate_limit" module:
#
#	post-proxy {
#		...
#		proxy_rate_limit
#		...
#	}
#
#  When running in the post-proxy section, the module will check if
#  rate limiting is needed.  When rate limiting starts, it will add an
#  attribute '&config:Proxy-Rate-Limit = yes'.  This lets you know
#  when rate limiting starts.  That attribute can be checked in the
#  "Post-Auth-Type Reject" section.
#
#  The module also logs an INFO message when rate limiting starts or
#  stops for a particular key.  The module will NOT log anything for
#  packets which are rate limited.  The idea is that if a bad client
#  is sending 1000 packets per second, you don't want to fill up the
#  logs with 1000 messages that say all the same thing.
#
#  The module can also be listed in the "authorize" section.  Listing
#  it there as the first module allows the server to reject bad
#  packets as quickly as possible, while doing zero additional work
#  for policies, database lookups, etc.
#
#  If it is listed in the "authorize" section, then it should not be
#  listed in the "pre-proxy" section.
#

#
#  The module configuration.
#
proxy_rate_limit {
	#
	#  The key used to track entries.
	#
	#  For now, the key is not configurable, and is hard-coded to be the expansion below.
	#
#	key = "%{User-Name}%{Calling-Station-Id}

	#
	#  This limits the maximum number of entries which are
	#  tracked.  If the table becomes full, then older entries
	#  will be evicted to make room for new entries.
	#
	max_entries = 2048

	#
	#  The idle timeout period, or lifetime of entries.  If we do
	#  not see packets for a device within this time limit, then
	#  the entry is expired.
	#
	idle_timeout = 10

	#
	#  The suppression period.  If a client retransmits more than
	#  "count" packets during this time, rate limiting will start,
	#  and the proxy will send a reject for subsequent packets.
	#
	window = 1

	#
	#  The suppression count.  If a client retransmits more than
	#  this many packets during "window", rate limiting will
	#  start, and the proxy will send a reject for subsequent packets.
	#
	count = 1
}
