ProFTPD module 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.

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.

The most current version of mod_ban is distributed with the proftpd source.

Author

Please contact TJ Saunders <tj at castaglia.org> with any questions, concerns, or suggestions regarding this module.

Directives

Control Actions


BanCache

Syntax: BanCache driver
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_ban
Compatibility: 1.3.4rc2 and later

The BanCache directive configures a driver to use for caching ban entries. Depending on the compile-time options, the following drivers are supported:


BanCacheOptions

Syntax: BanCacheOptions opt1 ... optN
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_ban
Compatibility: 1.3.4rc2 and later

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.

Example:

  BanCacheOptions UseJSON

The currently implemented options are:


BanControlsACLs

Syntax: BanControlsACLs actions|"all" "allow"|"deny" "user"|"group" list
Default: None
Context: server config
Module: mod_ban
Compatibility: 1.2.10rc1 and later

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.

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


BanEngine

Syntax: BanEngine on|off
Default: off
Context: server config
Module: mod_ban
Compatibility: 1.2.10rc1 and later

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.


BanLog

Syntax: BanLog path|"none"
Default: None
Context: server config, <Global>
Module: mod_ban
Compatibility: 1.2.10rc1 and later

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.

If path is "none", no logging will be done at all.


BanMessage

Syntax: BanMessage mesg
Default: None
Context: server config, <Global>
Module: mod_ban
Compatibility: 1.2.10rc1 and later

The BanMessage directive configures a message that will be sent to clients that have been banned. This message may contain the following variables:

Example:

  BanMessage "Host %a has been banned"


BanOnEvent

Syntax: BanOnEvent event freq expires [mesg]
Default: None
Context: server config, <Global>
Module: mod_ban
Compatibility: 1.2.10rc1 and later

The BanOnEvent directive is used to configure a "rule" that is triggered whenever the named event occurs. The currently supported events are:

Directive Class/Host/User Ban
AnonRejectPasswords Host ban
BadProtocol Host ban
ClientConnectRate Host ban
EmptyPassword Host ban
MaxClientsPerClass Class ban
MaxClientsPerHost Host ban
MaxClientsPerUser User ban
MaxCommandRate Host ban
MaxConnectionsPerHost Host ban
MaxHostsPerUser User ban
MaxLoginAttempts Host ban
MaxLoginAttemptsFromUser User@Host ban
RootLogin Host ban
TimeoutIdle Host ban
TimeoutLogin Host ban
TimeoutNoTransfer Host ban
TLSHandshake Host ban
UnhandledCommand Host ban

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
where N is the number of occurrences, and hh:mm:ss specifies a number of hours, minutes, and seconds. This parameter says that if N occurrences of event happen within the given time interval, then a ban is automatically added. The IP address of the connecting client is banned when the following event rules are triggered: AnonRejectPasswords, BadProtocol, MaxCommandRate, MaxClientsPerHost, MaxConnectionsPerHost, MaxLoginAttempts, TimeoutIdle, TimeoutNoTransfer, and UnhandledCommand. The class of the connected client, if any, is banned when a rule for MaxClientsPerClass is triggered. Rules for MaxClientsPerUser and MaxHostsPerUser will cause the connected username to be banned.

The duration should be formatted as:

  hh:mm:ss
and specifies the numbers of hours, minutes, and seconds that the automatic ban generated a BanOnEvent rule lasts. Unlike bans added via the ban ftpdctl control action, automatic bans do not have infinite lifetimes.

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


BanOptions

Syntax: BanOptions opt1 ...
Default: None
Context: server config, <VirtualHost>, <Global>
Module: mod_ban
Compatibility: 1.3.7rc4 and later

The BanOptions directive is used to configure various optional behavior of mod_ban.

Example:

  BanOptions MatchAnyServer

The currently implemented options are:


BanTable

Syntax: BanTable path
Default: None
Context: server config
Module: mod_ban
Compatibility: 1.2.10rc1 and later

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.

Note that ban data is not kept across daemon stop/starts. That is, once proftpd is shutdown, all current ban data is lost.


Control Actions


ban

Syntax: ftpdctl ban class|host|info|user|user@host [-s address#port] name1 [name2 ...]
Purpose: Add a ban or display ban information

The ban action is used to add bans to the mod_ban lists. For example, to ban a user:

  ftpdctl ban user dave
This will create a ban rule for user 'dave' for all virtual servers in your proftpd.conf. If you want to create such a ban rule, but only for one specific <VirtualHost>, use the -s command-line option, e.g.:
  ftpdctl ban user -s 1.2.3.4#21 dave
This example will create the user 'dave' ban rule for the <VirtualHost> handling IP address 1.2.3.4, port 21. The -s command-line option applies to host and class bans as well.

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
Banning a class works the same way:
  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
Or, if you wish to see more information, use the -v option:
  # 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)
It is also possible to see the state of ban event rules, using the -e option:
  # 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
This shows that no bans are currently in effect, and that a BanOnEvent has been configured for the MaxLoginAttempts event. That event has occurred once, and will need to happen one more time within 589 seconds in order for an automatic ban to be added.

See also: permit


permit

Syntax: ftpdctl permit class|host|user|user@host [-s address#port] name1 [name2 ...]
Purpose: Permit banned clients to connect

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


Installation

The mod_ban module is distributed with ProFTPD. Simply follow the normal steps for using third-party modules in ProFTPD, making sure to include the --enable-ctrls configure option, which mod_ban requires:
  $ ./configure --enable-ctrls --with-modules=mod_ban
To build mod_ban as a DSO module:
  $ ./configure --enable-ctrls --enable-dso --with-shared=mod_ban
Then follow the usual steps:
  $ 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 -c -i -d mod_ban.c


Usage

The mod_ban module implements its bans by checking if a client is banned, either by host or by class, when that client connects to the server. Banned clients are immediately disconnected. Banned users are checked after the client has sent the USER and PASS commands; if that user has been banned, the client is immediately disconnected.

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:

    ./configure CFLAGS="-DBAN_LIST_MAXSZ=1024" ...
or whatever your necessary ban list size is.

Logging
The mod_ban module supports trace logging, via the module-specific log channels:

Thus for trace logging, to aid in debugging, you would use the following in your proftpd.conf:
  TraceLog /path/to/ftpd/trace.log
  Trace ban:20
This trace logging can generate large files; it is intended for debugging use only, and should be removed from any production configuration.

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.

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