Hello everybody. I just finished this rc.firewall tonight and I thought I would ask those of you familiar with it what you think about it. Constructive criticism is welcome. It appears to work quite well, nmap, SATAN, SARA, Nessus all gave came up with nada, so it is doing it's job as far as I can tell. My experience has been with ipfilter on Free/OpenBSD and this is my first serious crack at a comprehensive rc.firewall for iptables v1.2.2.

The system I am using here is Slackware Linux 8.0 running the 2.4.16 kernel with the grsecurity patch grsecurity-1.9.2-2.4.16 and all of the security goodness options turned on.

I consider this rc.firewall to be BETA and would appreciate feedback on any issues you come across.

//note: This rc.firewall is built for my system, I do not use modules as they *can* pose a security risk as they are capable of being trojaned. A section to enable modules is included but commented out. If you have iptables load as a module but not at boot time, you will need to uncomment that section for this to be effective.

##################### and away we go
#!/bin/bash
#
# rc.firewall iptable packet filtering script by UberC0der
#
# Place this in /etc and chmod 700 it then run /etc/rc.firewall
# This script should flush your existing rules, so be sure and know what
# they were before you use this script. My personal suggestion is to
# to put them in a file named something like tables.rules under /etc.
# That way if you really *hate* this script you can always run
# `iptables --flush; iptables-restore /etc/tables.rules' and get your
# old rules back.
#
# My hope for this script is to be both a learning experience and
# perhaps, if all goes well, an outstanding rc.firewall. Enjoy, and
# remember, all comments, concerns, questions and suggestions are
# welcome.
#

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

#set up the variables
EXT_IF=eth0
EXT_IP=xxx.xxx.xxx.xxx/32 # for obvious reasons I left out my IP
EXT_NET=xxx.xxx.xxx.xxx/24 # ditto
LOCAL_ADDRS=127.0.0.0/8 xxx.xxx.xxx.xxx/32 # ditto again

#Turn on IP forwarding
echo Turining on IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# The next section will load the ip_tables module if your kernel does not

# do it at boot. As mentioned previously I do not use modules, however
# I included it for those of you who may. Just uncomment the middle two
# lines if you need the modules loaded.

# Load the ip_tables module
#echo Loading ip_tables module. #uncomment me to use me.
#/sbin/modprobe ip_tables || exit 1 #uncomment me to use me.
# I let the kernel dynamically load the other modules

echo Flush standard tables
iptables --flush INPUT
iptables --flush OUTPUT
iptables --flush FORWARD
echo Deny everything until firewall setup is complete
iptables --policy INPUT DROP
iptables --policy OUTPUT DROP
iptables --policy FORWARD DROP

CHAINS=`iptables -n -L |perl -n -e '/Chains\s+(\S+)/ && !($1 =~ /^(INPUT|FORWARD|OUTPUT)$/) && print "$1 "'`
echo Remove remaining chains:
echo $CHAINS
for chain in $CHAINS; do
iptbles --flush $chain
done

for chain in $CHAINS; do
iptables --delete-chain $chain
done

for net in $MASQ_NETS; do
# we delete all the rules so you can rerun the scripts without bloating your nat
# entries.
iptables -D POSTROUTING -t nat -s $MASQ_NETS -j MASQUERADE 2>/dev/null
iptables -A POSTROUTING -t nat -s $MASQ_NETS -j MASQUERADE || exit 1
done

iptables --policy FORWARD ACCEPT

# Create a target for logging and dropping packets
iptables --new LDROP 2>/dev/null
iptables -A LDROP --proto tcp -j LOG --log-level info
iptables -A LDROP --proto udp -j LOG --log-level info
iptables -A LDROP --proto icmp -j LOG --log-level info
iptables -A LDROP -f -j LOG --log-level emerg
iptables -A LDROP -j DROP

# Create a table for watching some accepted rules
iptables --new WATCH 2>/dev/null
iptables -A WATCH -m limit -j LOG --log-level warn
iptables -A WATCH -j ACCEPT

echo Special target for local addresses
iptables --new LOCAL 2>/dev/null
echo $LOCAL_ADDRS
for ip in $LOCAL_ADDRS; do
iptables -A INPUT --dst $ip -j LOCAL
iptables -A INPUT --src $ip -i ! lo -j DROP # some spoof protection
done

echo Drop and log every other incoming tcp connection attempts
iptables -A LOCAL -i ! lo --proto tcp --syn --j LDROP

echo Enforcing up ICMP policies, use iptables -L ICMP to check.
# note: we do not deny all ICMP messages as we may break some
# tcp/ip stuff along the way.
iptables --new ICMP 2>/dev/null
iptables -A INPUT --proto icmp -j LDROP
iptables -A ICMP -p icmp --icmp-type echo-reply -j ACCEPT
iptables -A ICMP -p icmp --icmp-type destination-unreachable -j WATCH
iptables -A ICMP -p icmp --icmp-type host-unreachable -j WATCH
iptables -A ICMP -p icmp --icmp-type protocol-unreachable -j WATCH
iptables -A ICMP -p icmp --icmp-type port-unreachable -j ACCEPT
iptables -A ICMP -p icmp --icmp-type fragmentation-needed -j LDROP
iptables -A ICMP -p icmp --icmp-type source-route-failed -j WATCH
iptables -A ICMP -p icmp --icmp-type network-unknown -j WATCH
iptables -A ICMP -p icmp --icmp-type host-unknown -j WATCH
iptables -A ICMP -p icmp --icmp-type network-prohibited -j WATCH
iptables -A ICMP -p icmp --icmp-type TOS-network-unreachable -j WATCH
iptables -A ICMP -p icmp --icmp-type TOS-host-unreachable -j WATCH
iptables -A ICMP -p icmp --icmp-type communication-prohibited -j WATCH
iptables -A ICMP -p icmp --icmp-type host-precedence-violation -j LDROP
iptables -A ICMP -p icmp --icmp-type precedence-cutoff -j LDROP
iptables -A ICMP -p icmp --icmp-type source-quench -j LDROP
iptables -A ICMP -p icmp --icmp-type redirect -j LDROP
iptables -A ICMP -p icmp --icmp-type network-redirect -j LDROP
iptables -A ICMP -p icmp --icmp-type TOS-network-redirect -j LDROP
iptables -A ICMP -p icmp --icmp-type TOS-host-redirect -j LDROP
iptables -A ICMP -p icmp --icmp-type echo-request -j WATCH
iptables -A ICMP -p icmp --icmp-type router-advertisement -j LDROP
iptables -A ICMP -p icmp --icmp-type router-solicitation -j LDROP
iptables -A ICMP -p icmp --icmp-type time-exceeded -j WATCH
iptables -A ICMP -p icmp --icmp-type ttl-zero-during-transit -j WATCH
iptables -A ICMP -p icmp --icmp-type ttl-zero-during-reassembly -j WATCH
iptables -A ICMP -p icmp --icmp-type ip-header-bad -j WATCH
iptables -A ICMP -p icmp --icmp-type required-option-missing -j WATCH
iptables -A ICMP -p icmp --icmp-type timestamp-request -j LDROP
iptables -A ICMP -p icmp --icmp-type timestamp-reply -j LDROP
iptables -A ICMP -p icmp --icmp-type address-mask-request -j LDROP
iptables -A ICMP -p icmp --icmp-type address-mask-reply -j LDROP
iptables -A ICMP -p icmp -j LDROP

echo Authorize tcp traffic.
iptables -A INPUT --proto tcp -j ACCEPT

# The following are my specific rules, please be sure and modify these
# to match whatever your box is set up for. example: if you run a mail
# server you don't want to drop all tcp to port 25.

# Here I am blocking specific ports for my needs.
iptables -A INPUT -i ! lo -p 255 -j DROP # no connections to raw sockets allowed
iptables -A INPUT -i ! lo -p tcp -m tcp --dport 1:6660 -j LDROP
iptables -A INPUT -i ! lo -p tcp -m tcp --dport 6680:27900 -j LDROP

echo Authorize packet output.
iptables --policy OUTPUT ACCEPT

# Here again, these are my rules, normally you will be safe blocking udp
# below 1024.

echo Drop and log all udp below 27900.
iptables -A INPUT -i ! lo --proto udp --dport :27899 -j LDROP

# imho rpc is Evil! I don't like it, comment this out or remove it if you feel
# that you must have rpc.
echo Drop rpc dynamic udp port:
RPC_UDP=`rpcinfo -p localhost|perl -n -e '/.*udp\s+(\d+)\s+/ && print $1, ~\n |sort -u`
echo $RPC_UDP
for port in $RPC_UDP; do
iptables -A LOCAL -i ! lo --proto udp --dport $port -j LDROP
done

# I play Quake and other games so I need udp +29700 to be allowed to
# accept connections. Once again please modify this to suite your
# needs.

echo Authorize udp above 27900.
iptables -A INPUT --proto udp --dport 27900: -j ACCEPT


########
# Disclaimer: the formatting in vi was more clean, once I pasted it in here
# it did't look so nice.
########