| lockout What it isAs everyone knows, or should know, firewalls are access control
locks for your computer. Let in the good, keep out the bad.
Unfortunately, static (unchanging) firewalls only block (or more
correctly, allow in) specific data. For example, say user A is trying
to attack something you have blocked – no problem, right?
That's the point of the firewall. Now let's say the same user A is
trying to use a service you provide, the web server for example.
Chances are he's trying to break into your computer through
the web server. Not so good. Hence, lockout. lockout monitors system logs looking
for possible attacks. When found, the offending IP address is
blocked. The logs are parsed using extended regular expression style
rules defined in the configuration, so the possibilities are endless.
Unlike other systems that run as cron jobs (minimum latency –
one minute) lockout monitors the logs
continuously via a named pipe, so attacks can be thwarted very
quickly. The flow for lockout is simple: the
first time a rule matches, the offending address is put on a
`pending' list and not blocked. If the same address matches any rule
a configured number of times, it is moved to the `blocked' list and a
firewall block is placed. It will not be removed until a configured
amount of time has elapsed. If the address is on the pending list
long enough (not moved to the blocked list) it will be expired. Blocking the first bad packet is not a good idea – imagine
if the rule is checking for failed authentication instead of rogue
packets. In this case if you mistype your password once, you're
locked out! The packaged rules and examples catch the three problems I see
most, but as I said above lockout is
fully configurable, so just about any rule can be defined. The three
problems I see: 
Usage
 
 lockout [-v] -c config 
 
 -v :
verbose logging -c config
: point to the configuration file (see below) 
 
 In addition, lockout responds to two
signals: USR1 –
dump the contents of the pending and locked lists to the log file. HUP
– close the log file and reopen (useful for logrotate) Buildinglockout is written in ANSI C, using
the minimum number of unix'isms. Simply untar the source and type
`make' Configuringlockout uses helper programs, defined
in the configuration file, to do the actual work of setting up the
firewall. By default these scripts use the `iptables'' command, so
that configuration will be described here. If you are using a
different firewall technique, you'll need to read the documentation
for that system. There are three parts to the configuration: setting up the
firewall, setting up syslog, and configuring lockout. Setting
up iptablesThe assumption is you've a firewall setup, and any packet not
explicitly allowed by the firewall is considered rogue, a possible
attack, and should be stopped. This isn't meant to be an in depth
tutorial about firewall configuration! Find that elsewhere. You'll
first need to create a new chain, ``offenders'': iptables -n offenders Once done, add it to your INPUT chain. You want it to be the first
rule. iptables -I INPUT 1
offenders You also need to add a LOG
entry. This is what catches rogue packets. It should be inserted
directly above the last entry, which should be DROP. When complete, your INPUT chain should look something like: Chain INPUT (policy
ACCEPT) target     prot opt
source               destination         
 offenders  0    -- 
anywhere             anywhere            
 fwallin    0    -- 
anywhere             anywhere            
 LOG        0    -- 
anywhere             anywhere            LOG level warning 
 DROP       0    -- 
anywhere             anywhere            
 A few things to note: offenders
is the rule that lockout populates. It
should be first to filter out known offenders quickly. Another
alternative is to put it between LOG
and DROP.
If you put it first you'll not notice if an attack is continuing
because it has been blocked. That means at some time in the future
the address will be unblocked even though it is the source of an
attack. If you put it after LOG
it will remain blocked until such time that it stops the attack. This
uses more CPU and I've not ever noticed a problem. fwallin
should be whatever fire wall rules you have defined. At the end of
this document there is an example. LOG
is built-in. Any packets that make it to LOG
are suspect because they got past fwallin.
This will make the kernel send all of the packets to the system log. DROP
is also built-in. If you've a working firewall you likely already
have this as your last input rule. Setting
up sysloglockout
works by reading from a named pipe and parsing the results. syslogd
must be setup to send information to this pipe. Start by making a
directory for lockout. I put it in
/var/lib/lockout.
Once there, create the named pipe (the default is lockout.pipe,
but it can be anything you want). The command is mkfifo. Next you'll need to add the
following line to /etc/syslog.conf: # # used by lockout # kern.*;auth.*        
          |/var/lib/lockout/lockout.pipe This simply means send
anything from the kernel or authentication logs to
/var/lib/lockout/lockout.pipe. Remember, after doing this
you'll need to restart syslogd and, as I've discovered, klogd. Under
debian this done with: /etc/init.d/sysklogd
restart /set/init.d/klogd
restart Configuring
lockoutThe included lockout
configuration file is completely documented, and more likely to be up
to date than this, but below is a description of its contents. As is
typical for configuration files, blank lines are ignored, and a '#'
denotes the beginning of a comment which lasts to the end of the
line. The maximum length of a line is 1023 bytes. String values must
be enclosed in double quotes. 
	
	
	
	
		
			| Value | Default | Explanation |  
			| FLUSH | ``./iptables_flush.sh'' | Command to execute when
				lockout starts which will flush all
				lockout addresses from the firewall. |  
			| BLOCK | ``./iptables_block.sh'' | Command to execute to
				block an address. A list of IP addresses is passed as parameters. |  
			| UNBLOCK | ``./iptables_unblock.sh'' | Command to execute to
				unblock an address. A list of IP addresses is passed as
				parameters. |  
			| ADDR_MAX | 512 | Maximum number of
				addresses to pass to BLOCK and UNBLOCK |  
			| STATE | ``/var/lib/lockout/state'' | Holds the current list of
				blocked addresses in the event lockout
				must be restarted. |  
			| LOG | ``/var/log/lockout.log'' | A simple log so you can
				see what's happening. |  
			| PIPE | ``/var/lib/lockout/lockout.pipe'' | The location of the named
				pipe created above. |  
			| IGNORE | None | Some addresses should
				never be blocked. For example, your default gateway. Any address
				listed here will never be blocked. Only one address per IGNORE
				line. |  
			| lockout_MIN | 259200 | The minimum number of
				seconds an address will be blocked. This default is three days. |  
			| lockout_JITTER | 172800 | An address will be blocked
				between lockout_MIN
				and lockout_MIN +
				lockout_JITTER
				seconds. This prevents someone from attacking you & knowing
				he'll be free to do so again in a given amount of time. |  
			| PENDING_MAX | 300 | The maximum number of
				seconds a possible offender stays on the pending list. |  
			| EXPIRE_FREQUENCY | 60 | How often to run the
				expire routine. |  
			| RULE | None | See below. |  
 
 The rules are defined, one per
line, as follows: RULE
“title:count:regular expression” title
is used to define which rule a particular address hit.count
tells lockout how many times a rule must
be hit before the address moves from the pending list to the blocked
list.
 regular
expression is just that. It is assumed that when the
offending IP address or host name will be the first thing not matched
by the regular expression. Here's an example: RULE “firewall:3:^\w{3} [
:0-9]{11} [._[:alnum:]-]+ kernel: IN=eth[[:digit:]]+ OUT=
MAC=[0-9:a-fA-F]{41} SRC=” The title is, `firewall.' It
must hit at least three times before the offender is blocked. 
Sample lockout Configuration File# Commands
FLUSH    “./iptables_flush.sh”
BLOCK    “./iptables_block.sh”
UNBLOCK  “./iptables_unblock.sh”
ADDR_MAX 512
# Various file locations.
STATE “/var/lib/lockout/state”
LOG   “/var/log/lockout.log”
PIPE  “/var/lib/lockout/lockout.pipe”
# One or more IGNORE clauses can be used to ignore certain
# addresses. You don't ever want to block your default gateway.
# this can be either an address or a host name
IGNORE 10.10.10.1  # default gateway
IGNORE 10.10.10.2  # me
#
# a lockout will last between lockout_MIN and lockout_MIN + lockout_JITTER
# seconds. The default is 3 - 5 days.
#
lockout_MIN    259200
lockout_JITTER 172800
#
# When an address is first seen, it goes onto the pending list. If it is
# not seen again within PENDING_MAX seconds it is removed.
#
PENDING_MAX 300
#
# determine how often to run the address expire routine
# (# of seconds between iterations)
#
EXPIRE_FREQUENCY 60
#
# rules are simply extended regular expressions. The format is:
# RULE=name:ct:expr
#   name -- rule name for logging which rule was matched
#   ct   -- number of times an offender must be seen before
#           moving from the pending list to the blocked list
#   expr -- goes to the end of the line
# nb: line length is limited to 1023 characters
#
# match iptables -- catches any packet not allowed by the firewall
#
RULE “firewall:3:^\w{3} [ :0-9]{11} [._[:alnum:]-]+ kernel: IN=eth[[:digit:]]+ OU
T= MAC=[0-9:a-fA-F]{41} SRC=”
#
# match authentication failures
#
RULE “auth:3:^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sshd\[[0-9]+\]: \(pam_unix\) auth
entication failure; .* rhost=”
#
# match bad password (probably redundant as this should be caught above)
#
RULE “badpass:3:^\w{3} [ :0-9]{11} [._[:alnum:]-]+ sshd\[[0-9]+\]: Failed passwor
d for .* from[ ]*”
Notes and BugsA downside to this technique is if many computers are sharing a
single address (common for home and small businesses), if one machine
is sending bad packets none of the other machines on that
address will be able to get through to your services. I have not
found this to be an issue in practice. I also believe protecting my
computer is paramount. As of this writing there are no known bugs. The following will be seen in the log always: MMM dd hh:mm:ss Added xxx.yyy.zzz.www to pending (matched rulename)
MMM dd hh:mm:ss Expired xxx.yyy.zzz.www from list after DD hh:mm:ss
MMM dd hh:mm:ss Moved xxx.yyy.zzz.www to blocked (matched rulename) 
 
 These will only be seen if “-v” is specified: MMM dd hh:mm:ss Pending xxx.yyy.zzz.www (matched rulename)
MMM dd hh:mm:ss Blocked xxx.yyy.zzz.www (matched rulename)
 
Finally, these will be seen when the USR1
signal is caught (ct is the number of times an address has been seen,
the time is the time since last seen): MMM dd hh:mm Pending (nn entries)
MMM dd hh:mm       xxx.yyy.zzz.www   ct days hh:mm:ss
...
MMMM dd hh:mm Blocked (nn entries)
MMM dd hh:mm       xxx.yyy.zzz.www   ct days hh:mm:ss
... 
Sample firewall rulesThis is the shell script I use to setup my iptables #!/bin/sh
#
# set the default input to DENY (nothing gets in)
# flush all chains
# delete the fwallin chain
#
iptables -P INPUT ACCEPT
iptables -F
iptables -X fwallin
#
# the firewall chain will be called `fwallin'
#
iptables -N fwallin
iptables -N offenders
#
# allow anything from/to the loopback
#
iptables -A fwallin -i lo -j ACCEPT
#
#
# allow TCP connections & transactions to ports 22, 25, 53, 80
# (ssh, email, dns, www)
#
iptables -A fwallin -p TCP -d 0/0 --destination-port 22 -j ACCEPT
iptables -A fwallin -p TCP -d 0/0 --destination-port 25 -j ACCEPT
iptables -A fwallin -p TCP -d 0/0 --destination-port 53 -j ACCEPT
iptables -A fwallin -p TCP -d 0/0 --destination-port 80 -j ACCEPT
#
# allow any established TCP connections, but don't allow
# packets with only the SYN bit set
#
iptables -A fwallin -p TCP -d 0/0 --destination-port 0:65535 ! --syn -j ACCEPT
#
# allow UDP to port 53 (dns)
#
iptables -A fwallin -p udp -d 0/0 --destination-port 53 -j ACCEPT
iptables -A fwallin -p udp -s 0/0 --source-port 53 -j ACCEPT
#
# allow UDP to/from port 123 (ntp)
#
iptables -A fwallin -p udp -d 0/0 --destination-port 123 -j ACCEPT
iptables -A fwallin -p udp -s 0/0 --source-port 123 -j ACCEPT
#
# allow all ICMP messages
#
iptables -A fwallin -p icmp -j ACCEPT
#
# deny everything else
#
iptables -A INPUT -j offenders
iptables -A INPUT -j fwallin
iptables -A INPUT -j LOG
iptables -A INPUT -j DROP
 |