# http://www.cs.princeton.edu/~jns/security/iptables/index.html
# prepared by james c. stephens
# (jns@gfdl.noaa.gov)
#!/bin/bash
#
# load appropriate modules.
modprobe ip_tables
modprobe ip_conntrack
modprobe ip_conntrack_ftp
# these lines are here in case rules are already in place and the script is ever rerun on the fly.
# we want to remove all rules and pre-exisiting user defined chains and zero the counters
# before we implement new rules.
iptables -f
iptables -x
iptables -z
# set up a default drop policy for the built-in chains.
# if we modify and re-run the script mid-session then (because we have a default drop
# policy), what happens is that there is a small time period when packets are denied until
# the new rules are back in place. there is no period, however small, when packets we
# dont want are allowed.
iptables -p input drop
iptables -p forward drop
iptables -p output drop
## ===========================================================
## some definitions:
nameserver_1=”x.x.x.x”
nameserver_2=”x.x.x.x”
broadcast=”x.x.x.255″
loopback=”127.0.0.0/8″
class_a=”10.0.0.0/8″
class_b=”172.16.0.0/12″
class_c=”192.168.0.0/16″
class_d_multicast=”224.0.0.0/4″
class_e_reserved_net=”240.0.0.0/5″
p_ports=”0:1023″
up_ports=”1024:65535″
tr_src_ports=”32769:65535″
tr_dest_ports=”33434:33523″
## ============================================================
## kernel flags
# to dynamically change kernel parameters and variables on the fly you need
# config_sysctl defined in your kernel. i would advise the following:
# disable response to ping.
/bin/echo “1” > /proc/sys/net/ipv4/icmp_echo_ignore_all
# disable response to broadcasts.
# you dont want yourself becoming a smurf amplifier.
/bin/echo “1” > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
# dont accept source routed packets. attackers can use source routing to generate
# traffic pretending to be from inside your network, but which is routed back along
# the path from which it came, namely outside, so attackers can compromise your
# network. source routing is rarely used for legitimate purposes.
/bin/echo “0” > /proc/sys/net/ipv4/conf/all/accept_source_route
# disable icmp redirect acceptance. icmp redirects can be used to alter your routing
# tables, possibly to a bad end.
/bin/echo “0” > /proc/sys/net/ipv4/conf/all/accept_redirects
# enable bad error message protection.
/bin/echo “1” > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
# turn on reverse path filtering. this helps make sure that packets use
# legitimate source addresses, by automatically rejecting incoming packets
# if the routing table entry for their source address doesnt match the network
# interface theyre arriving on. this has security advantages because it prevents
# so-called ip spoofing, however it can pose problems if you use asymmetric routing
# (packets from you to a host take a different path than packets from that host to you)
# or if you operate a non-routing host which has several ip addresses on different
# interfaces. (note – if you turn on ip forwarding, you will also get this).
for interface in /proc/sys/net/ipv4/conf/*/rp_filter; do
/bin/echo “1” > ${interface}
done
# log spoofed packets, source routed packets, redirect packets.
/bin/echo “1” > /proc/sys/net/ipv4/conf/all/log_martians
# make sure that ip forwarding is turned off. we only want this for a multi-homed host.
/bin/echo “0” > /proc/sys/net/ipv4/ip_forward
# note: with connection tracking, all fragments are reassembled before being
# passed to the packet-filtering code so there is no ip_always_defrag switch as there
# was in the 2.2 kernel.
## ============================================================
# rules
## loopback
# allow unlimited traffic on the loopback interface.
iptables -a input -i lo -j accept
iptables -a output -o lo -j accept
## syn-flooding protection
# this rule maximises the rate of incoming connections. in order to do this we divert tcp
# packets with the syn bit set off to a user-defined chain. up to limit-burst connections
# can arrive in 1/limit seconds ….. in this case 4 connections in one second. after this, one
# of the burst is regained every second and connections are allowed again. the default limit
# is 3/hour. the default limit burst is 5.
#
iptables -n syn-flood
iptables -a input -i $iface -p tcp –syn -j syn-flood
iptables -a syn-flood -m limit –limit 1/s –limit-burst 4 -j return
iptables -a syn-flood -j drop
## make sure new tcp connections are syn packets
iptables -a input -i $iface -p tcp ! –syn -m state –state new -j drop
## fragments
# i have to say that fragments scare me more than anything.
# sending lots of non-first fragments was what allowed jolt2 to effectively “drown”
# firewall-1. fragments can be overlapped, and the subsequent interpretation of such
# fragments is very os-dependent (see this paper for details).
# i am not going to trust any fragments.
# log fragments just to see if we get any, and deny them too.
iptables -a input -i $iface -f -j log –log-prefix “iptables fragments: ”
iptables -a input -i $iface -f -j drop
## spoofing
# most of this anti-spoofing stuff is theoretically not really necessary with the flags we
# have set in the kernel above ……….. but you never know there isnt a bug somewhere in
# your ip stack.
#
# refuse spoofed packets pretending to be from your ip address.
iptables -a input -i $iface -s $ipaddr -j drop
# refuse packets claiming to be from a class a private network.
iptables -a input -i $iface -s $class_a -j drop
# refuse packets claiming to be from a class b private network.
iptables -a input -i $iface -s $class_b -j drop
# refuse packets claiming to be from a class c private network.
iptables -a input -i $iface -s $class_c -j drop
# refuse class d multicast addresses. multicast is illegal as a source address.
iptables -a input -i $iface -s $class_d_multicast -j drop
# refuse class e reserved ip addresses.
iptables -a input -i $iface -s $class_e_reserved_net -j drop
# refuse packets claiming to be to the loopback interface.
# refusing packets claiming to be to the loopback interface protects against
# source quench, whereby a machine can be told to slow itself down by an icmp source
# quench to the loopback.
iptables -a input -i $iface -d $loopback -j drop
# refuse broadcast address packets.
iptables -a input -i $iface -d $broadcast -j drop
## dns
# note: dns uses tcp for zone transfers, for transfers greater than 512 bytes (possible, but unusual), and on certain
# platforms like aix (i am told), so you might have to add a copy of this rule for tcp if you need it
# allow udp packets in for dns client from nameservers.
iptables -a input -i $iface -p udp -s $nameserver_1 –sport 53 -m state –state established -j accept
iptables -a input -i $iface -p udp -s $nameserver_2 –sport 53 -m state –state established -j accept
# allow udp packets to dns servers from client.
iptables -a output -o $iface -p udp -d $nameserver_1 –dport 53 -m state –state new,established -j accept
iptables -a output -o $iface -p udp -d $nameserver_2 –dport 53 -m state –state new,established -j accept
## ssh
# allow ssh outbound.
iptables -a input -i $iface -p tcp –sport 22 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 22 -m state –state new,established -j accept
## www
# allow www outbound to 80.
iptables -a input -i $iface -p tcp –sport 80 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 80 -m state –state new,established -j accept
# allow www outbound to 443.
iptables -a input -i $iface -p tcp –sport 443 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 443 -m state –state new,established -j accept
## telnet
# allow telnet outbound.
iptables -a input -i $iface -p tcp –sport 23 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 23 -m state –state new,established -j accept
## ftp
# allow ftp outbound.
iptables -a input -i $iface -p tcp –sport 21 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 21 -m state –state new,established -j accept
# now for the connection tracking part of ftp. this is discussed more completely in my section
# on connection tracking to be found here.
# 1) active ftp.
# this involves a connection inbound from port 20 on the remote machine, to a local port
# passed over the ftp channel via a port command. the ip_conntrack_ftp module recognizes
# the connection as related to the original outgoing connection to port 21 so we dont
# need new as a state match.
iptables -a input -i $iface -p tcp –sport 20 -m state –state established,related -j accept
iptables -a output -o $iface -p tcp –dport 20 -m state –state established -j accept
# 2) passive ftp.
# this involves a connection outbound from a port >1023 on the local machine, to a port >1023
# on the remote machine previously passed over the ftp channel via a port command. the
# ip_conntrack_ftp module recognizes the connection as related to the original outgoing
# connection to port 21 so we dont need new as a state match.
iptables -a input -i $iface -p tcp –sport $up_ports –dport $up_ports
-m state –state established -j accept
iptables -a output -o $iface -p tcp –sport $up_ports –dport $up_ports
-m state –state established,related -j accept
## smtp
# allow smtp outbound.
iptables -a input -i $iface -p tcp –sport 25 -m state –state established -j accept
iptables -a output -o $iface -p tcp –dport 25 -m state –state new,established -j accept
## auth server
# reject ident probes with a tcp reset.
# i need to do this for a broken mailhost that wont accept my mail if i just drop its ident probe.
iptables -a input -i $iface -p tcp –dport 113 -j reject –reject-with tcp-reset
## traceroute
# outgoing traceroute anywhere.
# the reply to a traceroute is an icmp time-exceeded which is dealt with by the next rule.
iptables -a output -o $iface -p udp –sport $tr_src_ports –dport $tr_dest_ports
-m state –state new -j accept
# icmp
# we accept icmp in if it is “related” to other connections (e.g a time exceeded (11)
# from a traceroute) or it is part of an “established” connection (e.g. an echo reply (0)
# from an echo-request (8)).
iptables -a input -i $iface -p icmp -m state –state established,related -j accept
# we always allow icmp out.
iptables -a output -o $iface -p icmp -m state –state new,established,related -j accept
## logging
# you dont have to split up your logging like i do below, but i prefer to do it this way
# because i can then grep for things in the logs more easily. one thing you probably want
# to do is rate-limit the logging. i didnt do that here because it is probably best not too
# when you first set things up …………….. you actually really want to see everything going to
# the logs to work out what isnt working and why. you cam implement logging with
# “-m limit –limit 6/h –limit-burst 5” (or similar) before the -j log in each case.
#
# any udp not already allowed is logged and then dropped.
iptables -a input -i $iface -p udp -j log –log-prefix “iptables udp-in: ”
iptables -a input -i $iface -p udp -j drop
iptables -a output -o $iface -p udp -j log –log-prefix “iptables udp-out: ”
iptables -a output -o $iface -p udp -j drop
# any icmp not already allowed is logged and then dropped.
iptables -a input -i $iface -p icmp -j log –log-prefix “iptables icmp-in: ”
iptables -a input -i $iface -p icmp -j drop
iptables -a output -o $iface -p icmp -j log –log-prefix “iptables icmp-out: ”
iptables -a output -o $iface -p icmp -j drop
# any tcp not already allowed is logged and then dropped.
iptables -a input -i $iface -p tcp -j log –log-prefix “iptables tcp-in: ”
iptables -a input -i $iface -p tcp -j drop
iptables -a output -o $iface -p tcp -j log –log-prefix “iptables tcp-out: ”
iptables -a output -o $iface -p tcp -j drop
# anything else not already allowed is logged and then dropped.
# it will be dropped by the default policy anyway …….. but lets be paranoid.
iptables -a input -i $iface -j log –log-prefix “iptables protocol-x-in: ”
iptables -a input -i $iface -j drop
iptables -a output -o $iface -j log –log-prefix “iptables protocol-x-out: ”
iptables -a output -o $iface -j drop