...making Linux just a little more fun!
The following features are discussed:
All of the features discussed in this article are extensions to
the packet matching modules of iptables. I used only two of these
extensions in the previous article: the --state
module
which allowed us to filter packets based on whether they were
NEW
, ESTABLISHED
, RELATED
or
INVALID
connections; and the multiport
extension, of which I will go into more detail on in this
article.
Some of the modules introduced in this article (marked with an asterisk) have not made their way into the default Linux kernel yet but a netfilter utility called "patch-o-matic" can be used to add them to your own kernel and this will be discussed at the end of the article.
multiport
multiport
module allows one to specify a number of
different ports in one rule. This allows for fewer rules and easier
maintenance of iptables configuration files. For example, if we
wanted to allow global access to the SMTP, HTTP, HTTPS and SSH
ports on our server we would normally use something like the
following:
-A INPUT -i eth0 -p tcp -m state --state NEW --dport ssh -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state NEW --dport smtp -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state NEW --dport http -j ACCEPT -A INPUT -i eth0 -p tcp -m state --state NEW --dport https -j ACCEPTUsing the
multiport
matching module, we can now write:
-A INPUT -i eth0 -p tcp -m state --state NEW -m multiport --dports ssh,smtp,http,https -j ACCEPTIt must be used in conjunction with either
-p tcp
or
-p udp
and only up to 15 ports may be specified. The
supported options are:
--sports port[,port,port...]
- matches source port(s)
--dports port[,port,port...]
- matches destination port(s)
--ports port[,port,port...]
- matches both source and destination port(s)
mport
* is another similar extension that
also allows you to specify port ranges, e.g. --dport
22,80,6000:6100
.
random
* or
nth
*random
and nth
extensions can be
used for load balancing. If, for example, you wished to balance
incoming web traffic between four mirrored web servers then you
could add either of the following rule sets to your
nat
table:
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 0 \ -j DNAT --to-destination 192.168.0.5:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 1 \ -j DNAT --to-destination 192.168.0.6:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 2 \ -j DNAT --to-destination 192.168.0.7:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m nth --counter 0 --every 4 --packet 3 \ -j DNAT --to-destination 192.168.0.8:80or:
-A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \ -j DNAT --to-destination 192.168.0.5:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \ -j DNAT --to-destination 192.168.0.6:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW -m random --average 25 \ -j DNAT --to-destination 192.168.0.7:80 -A PREROUTING -i eth0 -p tcp --dport 80 -m state --state NEW \ -j DNAT --to-destination 192.168.0.8:80The
nth
matching extension allows you to match the nth
packet received by the rule. There are up to 16 (0...15) counters
for matching the nth packets. The above four (nth
)
rules use counter 0 to count every 4th packet. Once the 4th packet
is received, the counter is reset to zero. The first rule matches
the 1st packet (--packet 0
) of every four counted, the
second rule matches the 2nd packet (--packet 0
), and
so on.
The random
matching extension allows you to match
packets based on a given probability. The first rule from the set
of random
rules above matches 25% (--average
25
) of the TCP connections to port 80 and redirects these to
the first mirrored web server. Of the 75% of connections not
matching on the first rule, 25% will match the second and a further
25% will match the third. The remaining 25% will be caught by the
fourth rule.
Another use of the random
extension would be to
simulate a faulty network connection to evaluate the performance of
networking hardware/software, etc.
limit
and iplimit
*limit
matching extension can be used to limit the
number of times a rule matches in a given time period while the
iplimit
extension can restrict the number of parallel
TCP connections from a particular host or network. These extensions
can be used for a variety of purposes:
-A FORWARD -m state --state NEW -p tcp -m multiport --dport http,https -o eth0 -i eth1 \ -m limit --limit 50/hour --limit-burst 5 -j ACCEPTThis rule assumes that we are acting as a proxy server where the external connection is via
eth0
and eth1
connects to our office network. The rule limits all of our internal
computers to only 50 new HTTP or HTTPS connections per hour and the
use of --limit-burst
prevents any one employee from
using up all 50 in one go. Packets can be matched
/day
, /hour
, /minute
or
/sec
.
The --limit-burst
parameter can be quite confusing
at first. In the above example, it will ensure that if all
employees are trying to access the Internet throughout the hour
then only 5 connections are made every 5 minutes. If 30 minutes
pass with no connections and then there is a sudden rush for the
remaining 30 minutes, only 5 connections will be permitted every
2.5 minutes. I once heard it explained as follows:
For everylimit
rule, there's a "bucket" containing "tokens". Whenever the rule matches, a token is removed and when the token count reaches zero, the rule doesn't match anymore.
--limit
is the bucket refill rate.
--limit-burst
is the bucket size (number of tokens that it can hold).
The iplimit
extension allows us to restrict the
number of parallel TCP connections from a particular host or
network. If, for example, we wanted to limit the number of HTTP
connections made by any single IP address to 5 we could use:
-A INPUT -p tcp -m state --state NEW --dport http -m iplimit --iplimit-above 5 -j DROP
recent
Connections to
Match Againstrecent
extension one can dynamically
create a list of IP addresses that match a rule and then match
against these IPs in different ways later. One possible use would
be to create a "temporary" bad-guy list by detecting possible port
scans and to then DROP
all other connections from the
same source for a given period of time
Port 139 is one of the most dangerous ports for Microsoft
Windows® users as it is through this port that the Windows file
and print sharing service runs. This also makes this port one of
the first scanned by many port scanners or potential hackers and a
target for many of the worms around today. We can use the
recent
matching extension to temporarily block any IP
from connecting with our machine that scans this port as
follows:
-A FORWARD -m recent --name portscan --rcheck --seconds 300 -j DROP -A FORWARD -p tcp -i eth0 --dport 139 -m recent --name portscan --set -j DROPNow anyone trying to connect to port 139 on our firewall will have all of their packets dropped until 300 seconds has passed. The supported options include:
--name name
- The name of the list to store the IP in or check it against. If no name is given then
DEFAULT
will be used--set
- This will add the source address of the packet to the list. If the source address is already in the list, this will update the existing entry.
--rcheck
- This will check if the source address of the packet is currently in the list.
--update
- This will check if the source address of the packet is currently in the list. If it is then that entry will be updated and the rule will return true.
--remove
- This will check if the source address of the packet is currently in the list and if so that address will be removed from the list and the rule will return true.
--seconds seconds
- This option must be used in conjunction with one of
--rcheck
or--update
. When used, this will narrow the match to only happen when the address is in the list and was seen within the last given number of seconds.--hitcount hits
- This option must be used in conjunction with one of
--rcheck
or--update
. When used, this will narrow the match to only happen when the address is in the list and packets had been received greater than or equal to the given value. This option may be used along with `seconds' to create an even narrower match requiring a certain number of hits within a specific time frame.
string
* in a
Packet's Data Payloadstring
extension allows one to match a string
anywhere in a packet's data payload. Although this extension does
have many valid uses, I would strongly advise caution. Let's say,
for example, that our Linux firewall is protecting an internal
network with some computers running Microsoft Windows® and we
would like to block all executable files. We might try something
like:
-A FORWARD -m string --string '.com' -j DROP -A FORWARD -m string --string '.exe' -j DROPThis has a number of problems:
.com
' or '.exe
' is split
across two packets it will not be matchedtime
*time
module. This could be used to limit
staff web usage to lunch-times, to take each of a set of mirrored
web servers out of action for automated backups or system
maintenance, etc. The following example allows web access during
lunch hour:
-A FORWARD -p tcp -m multiport --dport http,https -o eth0 -i eth1 \ -m time --timestart 12:30 --timestop 13:30 --days Mon,Tue,Wed,Thu,Fri -j ACCEPTClearly the start and stop times are 24-hour with the format
HH:MM
. The day is a comma-separated list that is case
sensitive and made up of Mon
, Tue
,
Wed
, Thu
, Fri
,
Sat
and/or Sun
.
quota
*-A INPUT -p tcp -m quota --quota 2147483648 -j ACCEPT -A INPUT -j DROPYou can then view your usage with the following command:
$ iptables -v -L
You would also need to reset the quota every month manually (by
restarting iptables) or with a cron job. Clearly your computer
would need to be 'always-on' for this example to be of any use, but
there are also any other situations where the quota
extension would be useful.
As an interesting aside: this is actually how the
traceroute
command works. It sends a packet to the
destination with a TTL of 1 first and gets a reply from the first
intermediate host. It then sends a packet with a TTL of 2 and
receives a reply from the second intermediate host and so on until
it reaches its destination.
The usefulness of packet matching based on TTL value depends on your imagination. One possible use is to identify "man-in-the-middle" attacks. If you regularly connect from home to work you could monitor your TTL values and establish a reasonable maximum value at the receiving end. You can the use this to deny any packets that arrive with a higher TTL value as it may indicate a possible "man-in-the-middle" attack; someone intercepting your packets, reading/storing them and resending them onto the destination. There are of course "man-in-the-middle" methods that wouldn't alter the TTL value but, as always, security is never absolute, only incremental. TTL matching could also be used for network debugging or to find hosts with bad default TTL values.
As a simple example, let's reject all packets from a specific IP with a TTL of less than 40:
-A INPUT -s 1.2.3.4 -m ttl --ttl-lt 40 -j REJECTYou can also check for TTL values that are less than (
--ttl-gt
) or equal to (--ttl-eq
) a
particular value.
Patch-o-matic can be downloaded from the netfilter homepage,
http://www.netfilter.org/.
You will also need the source code for your kernel (if you are
using a kernel supplied with your distribution, install the
kernel-source
package or install a new kernel by
downloading the latest kernel source code from http://www.kernel.org/) and the source
code for iptables which you can also download from the netfilter
homepage. Once you have these, unpack them and execute the
runme
script from patch-o-matic as follows:
$ KERNEL_DIR=<path to the kernel source code>
IPTABLES_DIR=<path to the iptables source code> ./runme
extra
The script describes each new extension and asks whether or not to patch the kernel for it. Once that is finished you will need to recompile the kernel, the netfilter kernel modules and the iptables binaries. This is outside the scope of this article but you will find useful information on the following sites:
Barry O'Donovan graduated from the National University of Ireland, Galway
with a B.Sc. (Hons) in computer science and mathematics. He is currently
completing a Ph.D. in computer science with the Information Hiding Laboratory, University
College Dublin, Ireland in the area of audio watermarking.
Barry has been using Linux since 1997 and his current flavor of choice
is Fedora Core. He is a member of the Irish
Linux Users Group. Whenever he's not doing his Ph.D. he can usually be
found supporting his finances by doing some work for Open Hosting, in the pub with friends or running in the local
park.