SFS2X Docs / AdvancedTopics / extension-flood-filter
» Extension Flood Filter
Starting from release 2.19.0 we have introduced a new Extension Flood Filter that provides fine grained control over the packet rate of Extension requests. This can be used to limit the number of calls per second for specific requests and automatically set rules for warning and banning the offending client(s).
It also includes the ability to catch unknown Extension calls (i.e. requests for which there doesn't exist a request handler) and apply auto-ban rules as well.
Under normal circumstances, e.g. users playing with the official client app, there shouldn't be a concern about request spam, since limitations can be easily coded in the client itself. However it's also relatively easy for malicious users to reverse engineer a client made in JavaScript, Unity or Java and bypass such limitations.
Overview
In the diagram above we show a bird's eye view of the filter and its position in the Extension invocation chain. For each request handler defined in our Extension code (via the addRequestHandler methods) we can provide a limit expressed in number of calls per second.
For example we have defined a playerShoot request handler in our Extension and we've also set a limit of 4 requests/sec. If a client sends 50 calls in one second only the first 4 will be passed to the Extension and processed while the rest will be discarded. Additionally, based on the auto-ban rules, the sender will be either warned or banned.
The Extension Flood Filter is activated via code in the Extension, so let's take a look at how we can set it up.
Setup examples
The Extension Flood Filter is inactive by default. To activate it we need to call the initFloodFilter(...) method, available from the parent SFSExtension class.public class AntiFloodTestExtension extends SFSExtension { static final String PLAYER_SHOOT = "pShoot"; static final String PLAYER_MOVE = "pMove"; @Override public void init() { ExtensionFloodFilterConfig cfg = new ExtensionFloodFilterConfig(); cfg.banDurationMinutes = 120; cfg.maxFloodingAttempts = 3; cfg.secondsBeforeBan = 2; cfg.banMessage = "You are now banned. Reason: request flooding."; cfg.filterRules = Map.of ( PLAYER_SHOOT, 4, PLAYER_MOVE, 15 ); initFloodFilter(cfg); addRequestHandler(PLAYER_SHOOT, (sender, param) -> { trace("Shooting"); }); addRequestHandler(PLAYER_MOVE, (sender, param) -> { trace("Moving"); }); } }
The initializer method takes a ExtensionFloodFilterConfig object with the following properties:
- banDurationMinutes: duration of user ban. Default = 60 minutes
- secondsBeforeBan: delay before banning is executed, used to allow the user to receive the banishment warning. Default = 5 seconds
- banMode: modality of ban. Can be BY_NAME or BY_ADDRESS. Default = BY_NAME
- banMessage: a text message sent by the server before banning the user
- maxFloodingAttempts: maximum flooding attempts detected before the user is banned. Default = 5
- logFloodingAttempts: logs every flooding attempts. Note: can bloat the log files and hit the performance. Default = false
- filter rules: a map of rules where the key (String) is the name of the Extension request and the value (Integer) is the maximum number of requests per second allowed
- maxUnknownReqRate: maximum rate/sec of unkown requests, i.e. requests for which there is no request handler. This is useful to defend against random requests that might be sent to probe the Extension
Once this is done the filter is up and ready to do its job.
NOTE: when setting up the Extension we recommend to use the approach shown in the example above where each request name is defined as a constant and used to define both handlers and filters. This is to avoid typos that could lead to unexpected behaviors.
Limitations and suggestions
- Java support only: there is one main limitation with the Extension Flood Filter. It is only supported by Extensions that inherit from the SFSExtension class, which is the default for Java based Extensions, but not for those made in JavaScript or Python.
- Based on request name: the flood filter is based on request names only. If your client is calling two Extensions at the same time (e.g. Zone and Room) with identical request names they will count as the same request in the Extension Flood Filter. If this could be a problem make sure to differentiate those names and make them unique.
- Packet aggregation: when using TCP packets can be aggregated together if they're sent very rapidly. This is a feature known as the Nagle's algorithm. This in turn may trigger the Flood Filter when the actual packet rate is very close to the configured limit. For this reason it is usually recommended to set the request limit one or two units higher than the wanted value. For example: we want to limit the 'shoot' request to 5/sec. We suggest to configure it as 6 requests/sec. This will avoid that the occasional packet aggregation triggers the filter unnecessarily.
There is also an alternative, which is to enable the tcpNoDelay option under config/core.xml.