The
netfilter
firewall (available in Linux 2.4 and
later) allows for very flexible firewall manipulation from the
command line. Using iptables can take a while to get used to, but it
allows for a very expressive syntax that lets you create complex (and
hopefully useful ;) firewall rules.
Even if your machine isn't a
"real" firewall (that is, it only
has one network interface and isn't protecting other
machines) the filter functionality can be very useful. Suppose you
want to allow telnet access to this machine (just in case something
happens to ssh or its libraries) but
don't want to permit it from just anywhere on the
Net. You could use a tcpwrapper (by populating
/etc/hosts.allow and
/etc/hosts.deny, and setting up
/etc/inetd.conf appropriately). Or, you could
use iptables with a line like this:
iptables -A INPUT -t filter -s ! 208.201.239.36 -p tcp --dport 23 -j DROP
Generally,
most people want to permit
unrestricted access from trusted hosts, block all access from known
problem hosts, and allow something in between for everyone else. Here
is one method for using a whitelist,
blacklist, and restricted port policy simultaneously.
#!/bin/sh
#
# A simple firewall initialization script
#
WHITELIST=/usr/local/etc/whitelist.txt
BLACKLIST=/usr/local/etc/blacklist.txt
ALLOWED="22 25 80 443"
#
# Drop all existing filter rules
#
iptables -F
#
# First, run through $WHITELIST, accepting all traffic from the hosts and networks
# contained therein.
#
for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do
echo "Permitting $x..."
iptables -A INPUT -t filter -s $x -j ACCEPT
done
#
# Now run through $BLACKLIST, dropping all traffic from the hosts and networks
# contained therein.
#
for x in `grep -v ^# $BLACKLIST | awk '{print $1}'`; do
echo "Blocking $x..."
iptables -A INPUT -t filter -s $x -j DROP
done
#
# Next, the permitted ports: What will we accept from hosts not appearing
# on the blacklist?
#
for port in $ALLOWED; do
echo "Accepting port $port..."
iptables -A INPUT -t filter -p tcp --dport $port -j ACCEPT
done
#
# Finally, unless it's mentioned above, and it's an inbound startup request,
# just drop it.
#
iptables -A INPUT -t filter -p tcp --syn -j DROP
Be sure to specify all of the ports you'd like to
include in the $ALLOWED variable at the top of the script. If you
forget to include 22, you won't be able
to ssh into the box!
The /usr/local/etc/blacklist.txt file is
populated with IP addresses, host names, and networks like this:
1.2.3.4 # Portscanned on 8/15/02
7.8.9.0/24 # Who knows what evil lurks therein
r00tb0y.script-kiddie.coop # $0 s0rR33 u 31337 h4x0r!
Likewise, /usr/local/etc/whitelist.txt contains
the "good guys" that should be
permitted no matter what the other rules specify:
11.22.33.44 # My workstation
208.201.239.0/26 # the local network
Since we're only grabbing lines that
don't start with #, you can comment out an entire
line if you need to. The next time you run the script, any commented
entries will be ignored. We run an iptables -F
at the beginning to flush all existing filter entries, so you can
simply run the script again when you make changes to
blacklist.txt,
whitelist.txt, or the ports specified in
$ALLOWED.
Also note that this script only allows for TCP connections. If you
need to also support UDP, ICMP, or some other protocol, run another
pass just like the $ALLOWED for loop, but include your additional
ports and protocols (passing -p udp or
-p icmp to iptables, for
example).
Be careful about using whitelists. Any IPs or networks appearing on
this list will be permitted to access all ports on your machine. In
some circumstances, a clever miscreant may be able to send forged
packets apparently originating from one of those IPs, if they can
find out ahead of time (or logically deduce) what IPs appear on your
whitelist. This kind of attack is difficult to perform, but it is
possible. If you are particularly paranoid, you might only allow
whitelist addresses from networks that aren't
routable over the Internet but are used on your internal network.
It is extremely useful to have console access while working with new
firewall rules (you can't lock yourself out of the
console with iptables!) If you get confused
about where you are when working with iptables,
remember that you can always list out all rules with
iptables -L, and start over by issuing
iptables -F. If iptables -L
seems to hang, try iptables -L -n to show the
rules without doing any DNS resolution -- your rules might
accidentally be prohibiting DNS requests.
You can do a lot with simple filtering, but there's
much more to iptables than just the filter
target.
#!/bin/sh
#
# A simple firewall initialization script
#
WHITELIST=/usr/local/etc/whitelist.txt
ALLOWED="22 25 80 443"
#
# Drop all existing filter rules
#
iptables -F
#
# First, run through $WHITELIST, accepting all traffic from the hosts and networks
# contained therein.
#
#Allow localhost. For webbased mail.
iptables -A INPUT -t filter -s 127.0.0.1 -j ACCEPT
for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do
echo "Permitting $x..."
for port in $ALLOWED; do
echo "Accepting port $port..."
iptables -A INPUT -t filter -s $x -p tcp --dport $port -j ACCEPT
done
done
#
# Finally, unless it's mentioned above, and it's an inbound startup request,
# just drop it.
#
iptables -A INPUT -t filter -p tcp --syn -j DROP