mod_ban
The mod_ban module is designed to add dynamic "ban" lists to proftpd. A ban prevents the banned user, host, or class from logging in to the server; it does not prevent the banned user, host, or class from connecting to the server. mod_ban is not a firewall. The module also provides automatic bans that are triggered based on configurable criteria.
proftpd
This module is contained in the mod_ban.c file for ProFTPD 1.2.x/1.3.x, and is not compiled by default. Installation instructions are discussed here. Detailed documentation on mod_ban usage can be found here.
mod_ban.c
The most current version of mod_ban is distributed with the proftpd source.
Please contact TJ Saunders <tj at castaglia.org> with any questions, concerns, or suggestions regarding this module.
ban
permit
<VirtualHost>
<Global>
The BanCache directive configures a driver to use for caching ban entries. Depending on the compile-time options, the following drivers are supported:
BanCache
The BanCacheOptions directive is used to configure various optional caching behavior of mod_ban. Note: all of the configured BanCacheOptions parameters must appear on the same line in the configuration; only the first BanCacheOptions directive that appears in the configuration is used.
BanCacheOptions
Example:
BanCacheOptions UseJSON
The currently implemented options are:
MatchServer
This option tells mod_ban to ignore cached entries unless they match the IP address/port of the server handling the FTP session. There might be other servers adding their own entries to a common cache, for example; it is for these situations that the MatchServer option should be used, to avoid false positives.
UseJSON
This option tells mod_ban to store the ban rules in the cache as JSON-formatted data. This makes it possible for other tools to discover/display the cached ban rules.
Note that this option first appeared in proftpd-1.3.6rc2.
proftpd-1.3.6rc2
The BanControlsACLs directive configures access lists of users or groups who are allowed (or denied) the ability to use the actions implemented by mod_ban. The default behavior is to deny everyone unless an ACL allowing access has been explicitly configured.
BanControlsACLs
If "allow" is used, then list, a comma-delimited list of users or groups, can use the given actions; all others are denied. If "deny" is used, then the list of users or groups cannot use actions all others are allowed. Multiple BanControlsACLs directives may be used to configure ACLs for different control actions, and for both users and groups.
The actions provided by mod_ban are "ban" and "permit".
Examples:
# Allow only user root to ban and permit users BanControlsACLs all allow user root
The BanEngine directive enables or disables the banning of sessions by mod_ban. If it is set to off this module does no banning. Use this directive to disable the module instead of commenting out all mod_ban directives.
BanEngine
The BanLog directive is used to specify a log file for mod_ban reporting and debugging. The path parameter must be the full path to the file to use for logging. Note that this path must not be to a world-writeable directory and, unless AllowLogSymlinks is explicitly set to on (generally a bad idea), the path must not be a symbolic link.
BanLog
AllowLogSymlinks
If path is "none", no logging will be done at all.
The BanMessage directive configures a message that will be sent to clients that have been banned. This message may contain the following variables:
BanMessage
%a
%c
%u
BanMessage "Host %a has been banned"
The BanOnEvent directive is used to configure a "rule" that is triggered whenever the named event occurs. The currently supported events are:
BanOnEvent
AnonRejectPasswords
BadProtocol
ClientConnectRate
EmptyPassword
MaxClientsPerClass
MaxClientsPerHost
MaxClientsPerUser
MaxCommandRate
MaxConnectionsPerHost
MaxHostsPerUser
MaxLoginAttempts
MaxLoginAttemptsFromUser
RootLogin
TimeoutIdle
TimeoutLogin
TimeoutNoTransfer
TLSHandshake
UnhandledCommand
An event is generated whenever one of these limits is reached by a client.
The freq parameter should be formatted as:
N/hh:mm:ss
hh:mm:ss
The duration should be formatted as:
ftpdctl
An optional message, to be displayed to banned clients, can be configured. If no such optional message is configured using the BanOnEvent directive, then any BanMessage message will be displayed.
For example:
# Configure a rule to automatically ban scripts looking for anonymous # servers to which they can upload BanOnEvent AnonRejectPasswords 1/01:00:00 99:99:99 # Ban clients which connect too frequently. This rule bans clients # which connect more than 5 times within one minute. Include a special # message just for them. BanOnEvent ClientConnectRate 5/00:01:00 04:00:00 "Stop connecting frequently"
See also: BanMessage
The BanOptions directive is used to configure various optional behavior of mod_ban.
BanOptions
BanOptions MatchAnyServer
MatchAnyServer
By default, any ban entries are valid only for the <VirtualHost> handling the banned clients. This is intentional; the assumption is that there will be different clients, different use cases for the different <VirtualHost> sections.
However, some sites would like ban entries to be valid across <VirtualHost>, to match, or apply to any server. Use this option to enable this behavior.
The BanTable directive configures a path to a file that mod_ban uses for handling its ban data. The given path must be an absolute path. Note: this directive is required for mod_ban to function. It is recommended that this file not be on an NFS mounted partition.
BanTable
Note that ban data is not kept across daemon stop/starts. That is, once proftpd is shutdown, all current ban data is lost.
The ban action is used to add bans to the mod_ban lists. For example, to ban a user:
ftpdctl ban user dave
proftpd.conf
-s
ftpdctl ban user -s 1.2.3.4#21 dave
To ban specific hosts, you can use either IP addresses or DNS names:
ftpdctl ban host 1.2.3.4 5.6.7.8 ftpdctl ban host gw.evil.com
ftpdctl ban class anonftp
The info parameter is used to view information on current bans. Example listing:
# ftpdctl ban info ftpdctl: Banned Hosts: ftpdctl: 127.0.0.1
-v
# ftpdctl ban info -v ftpdctl: Banned Hosts: ftpdctl: 127.0.0.1 ftpdctl: Reason: MaxLoginAttempts autoban at Wed May 19 14:59:25 2004 ftpdctl: Expires: Wed May 19 14:59:55 2004 (in 24 seconds) ftpdctl: <VirtualHost> ServerName (1.2.3.4#21)
-e
# ftpdctl ban info -e ftpdctl: No bans ftpdctl: ftpdctl: Ban Event Entries: ftpdctl: Event: MaxLoginAttempts ftpdctl: Source: 127.0.0.1 ftpdctl: Occurrences: 1/2 ftpdctl: Entry Expires: 589 seconds
See also: permit
The permit action is used to remove a ban for users, hosts, and classes:
# ftpdctl permit user dave # ftpdctl permit user -s 1.2.3.4#21 dave # ftpdctl permit host 1.2.3.4 gw.evil.com # ftpdctl permit class anonftp
See also: ban
--enable-ctrls
$ ./configure --enable-ctrls --with-modules=mod_ban
$ ./configure --enable-ctrls --enable-dso --with-shared=mod_ban
$ make $ make install
For those with an existing ProFTPD installation, you can use the prxs tool to add mod_ban, as a DSO module, to your existing server:
prxs
$ prxs -c -i -d mod_ban.c
USER
PASS
Here is an example mod_ban configuration, demonstrating how to configure an automatic ban for MaxLoginAttempts:
MaxLoginAttempts 1 <IfModule mod_ban.c> BanEngine on BanLog /var/log/proftpd/ban.log BanTable /var/data/proftpd/ban.tab # If the same client reaches the MaxLoginAttempts limit 2 times # within 10 minutes, automatically add a ban for that client that # will expire after one hour. BanOnEvent MaxLoginAttempts 2/00:10:00 01:00:00 # Allow the FTP admin to manually add/remove bans BanControlsACLs all allow user ftpadm </IfModule>
By default, the mod_ban module allocate size for 512 bans. In practice, this has seemed to work well. However, if you need to allocate space for more bans, you will need to recompile proftpd, and use the CFLAGS environment variable like so:
CFLAGS
./configure CFLAGS="-DBAN_LIST_MAXSZ=1024" ...
Logging The mod_ban module supports trace logging, via the module-specific log channels:
TraceLog /path/to/ftpd/trace.log Trace ban:20
Frequently Asked Questions Question: Why does mod_ban not store ban data across daemon stop/starts? Answer: The mod_ban module was not designed to add yet another ACL mechanism to proftpd. For persistent access control, there is the <Limit LOGIN> section, the mod_wrap module, the /etc/ftpusers file, and various other mechanisms. The purpose of mod_ban is to provide dynamic, short-lived bans.
<Limit LOGIN>
mod_wrap
/etc/ftpusers
Question: What about having proftpd delay sending responses to clients, say by 30 seconds or so? Answer: This is a bad idea. It would allow malicious clients, who knew they were banned, to tie up your proftpd processes, since those processes would be taking up space, waiting before sending responses back to the client. This makes it possible for those clients to use the delaying as a Denial of Service attack, eventually tying up your available system resources with waiting proftpd processes.
Question: I have the following, taken from the example config above, configured for mod_ban, but it does not appear to be working. Why not? # If the same client reaches the MaxLoginAttempts limit 2 times # within 10 minutes, automatically add a ban for that client that # will expire after one hour. BanOnEvent MaxLoginAttempts 2/00:10:00 01:00:00 Answer: The most common reason is that the MaxLoginAttempts directive does not function the way that many assume it does. The above BanOnEvent rule says that the same client (i.e. source IP address) which reaches the MaxLoginAttempts limit 2 times within 10 minutes will be banned. If you test by connecting to proftpd, trying a bad password once, disconnecting, then connecting again and trying the same bad password again, you will not be hitting the MaxLoginAttempts limit. Remember that the MaxLoginAttempts directive configures a limit to the number of bad login attempts for the same connection; it does not configure limit on the number of bad login attempts across multiple connections. The default MaxLoginAttempts value for proftpd is 3. Which means that simply connecting, trying a bad login attempt once, then disconnecting, will not trigger the MaxLoginAttempts limit. This is why the example configuration given above explicitly configures the MaxLoginAttempts limit to be lower: MaxLoginAttempts 1 in order to make mod_ban behave the way that most administrators assume it will. If you have not explicitly configured MaxLoginAttempts lower, then this is probably why your BanOnEvent rule is not taking effect as you expect. Question: It looks like the BanTable file I configured is untouched: -rw-r--r-- 1 ftp ftp 0 2007-01-13 23:18 ban.table Does this mean that something is wrong, or that mod_ban is not using that file? Answer: A BanTable file is needed, just not in an obvious way. The mod_ban module stores its ban information in a SysV shared memory segment. The configured BanTable file is used a) to generate a unique name/ID for the shared memory segment to use (and to see if a segment for that name/ID already exists), and b) for locking, as when multiple sessions are trying to update the shared memory segment at the same time. But mod_ban does not write any data into that file itself, and hence the last-modified-time of the file, and the file size, does not change much. Question: How can I configure a whitelist of IP addresses, to be excluded from the effects of mod_ban? Answer: This can be done using a combination of Classes and the mod_ifsession module. For example: <Class whitelist> From ... </Class> <IfClass whitelist> # Turn the mod_ban module off for whitelisted clients BanEngine off </IfClass> <IfClass !whitelist> # Make sure the mod_ban module is on for clients that are not whitelisted BanEngine on </IfClass> Note that it is important to have both <IfClass> sections in your configuration. It is also important that for the above to work, when using shared/DSO modules, that mod_ban be loaded in your configuration before mod_ifsession: LoadModule mod_ban.c ... LoadModule mod_ifsession.c Otherwise, when parsing the configuration, mod_ban might not set all of the proper internal state for implementing the whitelists. Question: I would like to ban clients which try to login as root. How would I do this? Answer: You would use the BanOnEvent directive, with an event name of "mod_auth.root-login", thus: # Ban clients which try to login as root. This bans clients which # try root logins twice within 10 minutes, banning them for 6 hours. BanOnEvent mod_auth.root-login 2/00:10:00 06:00:00 © Copyright 2004-2022 TJ Saunders All Rights Reserved
# If the same client reaches the MaxLoginAttempts limit 2 times # within 10 minutes, automatically add a ban for that client that # will expire after one hour. BanOnEvent MaxLoginAttempts 2/00:10:00 01:00:00
The above BanOnEvent rule says that the same client (i.e. source IP address) which reaches the MaxLoginAttempts limit 2 times within 10 minutes will be banned. If you test by connecting to proftpd, trying a bad password once, disconnecting, then connecting again and trying the same bad password again, you will not be hitting the MaxLoginAttempts limit. Remember that the MaxLoginAttempts directive configures a limit to the number of bad login attempts for the same connection; it does not configure limit on the number of bad login attempts across multiple connections.
The default MaxLoginAttempts value for proftpd is 3. Which means that simply connecting, trying a bad login attempt once, then disconnecting, will not trigger the MaxLoginAttempts limit. This is why the example configuration given above explicitly configures the MaxLoginAttempts limit to be lower:
MaxLoginAttempts 1
Question: It looks like the BanTable file I configured is untouched:
-rw-r--r-- 1 ftp ftp 0 2007-01-13 23:18 ban.table
Answer: A BanTable file is needed, just not in an obvious way. The mod_ban module stores its ban information in a SysV shared memory segment. The configured BanTable file is used a) to generate a unique name/ID for the shared memory segment to use (and to see if a segment for that name/ID already exists), and b) for locking, as when multiple sessions are trying to update the shared memory segment at the same time. But mod_ban does not write any data into that file itself, and hence the last-modified-time of the file, and the file size, does not change much.
Question: How can I configure a whitelist of IP addresses, to be excluded from the effects of mod_ban? Answer: This can be done using a combination of Classes and the mod_ifsession module. For example:
mod_ifsession
<Class whitelist> From ... </Class> <IfClass whitelist> # Turn the mod_ban module off for whitelisted clients BanEngine off </IfClass> <IfClass !whitelist> # Make sure the mod_ban module is on for clients that are not whitelisted BanEngine on </IfClass>
<IfClass>
It is also important that for the above to work, when using shared/DSO modules, that mod_ban be loaded in your configuration before mod_ifsession:
LoadModule mod_ban.c ... LoadModule mod_ifsession.c
Question: I would like to ban clients which try to login as root. How would I do this? Answer: You would use the BanOnEvent directive, with an event name of "mod_auth.root-login", thus:
# Ban clients which try to login as root. This bans clients which # try root logins twice within 10 minutes, banning them for 6 hours. BanOnEvent mod_auth.root-login 2/00:10:00 06:00:00