IP Tables
29 Nov 2004 @ 02:28PM

Updated: 27 Jan 2010 @ 03:20PM
##########################################################################################
##                                                                                      ##
##                                    IPTables Firewall Script                          ##
##                                       by Satis                                       ##
##                                                                                      ##
##########################################################################################
##                                                                                      ##
##  This firewall script is written for a Linux Installation and Administration class   ##
##  and is designed for an end-computer based on a home network.  This end-computer     ##
##  is running Apache web server and SSH services.  The script allows access to these   ##
##  services to machines running within the network, but denies external access.        ##
##                                                                                      ##
##  This is based off a firewall script provided at the following web page:             ##
##  http://iptables-tutorial.frozentux.net/chunkyhtml/index.html                        ##
##                                                                                      ##
##  Additional resources:                                                               ##
##                    /sbin/iptables --help                                             ##
##                    man iptables                                                      ##
##                    http://www.linuxquestions.org/questions/archive/9/2003/02/4/9801  ##
##                                                                                      ##
##  The commented script follows below.                                                 ##
##                                                                                      ##
##########################################################################################

##
## Get your current IP address.
##

IP=`/sbin/ifconfig eth0 | grep 'inet addr' | awk '{print $2}' | sed -e 's/.*://'`
## This sets a variable (IP).  It calls ifconfig and then greps the line with 'inet addr' in
## it.  It then pipes it through an awk getting the second ouput ($2)  which returns just the
## inet addr portion.  Finally it's piped through sed, which removes  everything but the 
## actual IP address.

##
## Clear all existing rules and tables.
##

/sbin/iptables -F
## Flush all existing rules on all existing table.

/sbin/iptables -X
## Delete all existing user-tables.

##
## Set default policies
##

/sbin/iptables -P INPUT DROP
## This sets the default policy for the INPUT table to drop.  Any packet which doesn't match
## a rule while passing through the INPUT table is dropped.

/sbin/iptables -P OUTPUT DROP
## This sets the default policy for the OUTPUT table to drop.

/sbin/iptables -P FORWARD DROP
## This sets the default policy for the FORWARD table to drop.

##
## Create user-defined tables.  User-defined tables need to be created prior to references to
## that table.
##

/sbin/iptables -N bad_tcp_packets 
## This creates a table called 'bad_tcp_packets'.  This table is used to drop any tcp packets which
## are considered 'bad'.  More specific information will be provided in the 'bad_tcp_packets'
## setup.

/sbin/iptables -N allowed         
## This creates a table called 'allowed'.  This will be final processing of packets that we're
## allowing.  See that table's setup below for more specific information.

/sbin/iptables -N tcp_packets     
## This creates a table called 'tcp_packets'.  TCP packets are forwarded to this table for
## processing.  See that table's setup below for more specific information.

/sbin/iptables -N udp_packets    
## This creates a table called 'udp_packets'.  UDP packets are forwarded to this table for
## processing.  See that table's setup below for more specific information.

/sbin/iptables -N icmp_packets 
## This creates a table called 'icmp_packets'.  ICMP packest are forwarded to this table for
## processing.  See that table's setup below for more specific information. 

##
## Define the INPUT table.  Here we define the rules for our INPUT table.  Any packets coming
## into the machine go through this table.
##

/sbin/iptables -A INPUT -p TCP -j bad_tcp_packets
## This adds a rule to the INPUT table (-A), for all TCP packets (-p), that makes them jump (-j)
## to the 'bad_tcp_packets' table. If they make it through that table without being dropped or
## accepted, they then come back to the INPUT table for further processing.

/sbin/iptables -A INPUT -p TCP -i eth0 -s 192.168.1.50 --dport 80 -j DROP
## This adds a rule to the INPUT table for all TCP packets coming into interface eth0 (-i), with
## a source address of 192.168.1.50 (-s), destined for port 80 (--dport) and drop them.
## 192.168.1.50 is my home router's ip address.  This will basically take any attempts to reach
## the web server from the router (or through the router from the general internet) and drop them.

/sbin/iptables -A INPUT -p ALL -i lo -s 127.0.0.1 -j ACCEPT
## This adds a rule to the INPUT table for all protocols (-p ALL) going to the local interface
## (-i lo) from a source address of 127.0.0.1 (-s) and accepts them.  Basically, any traffic
## coming from the server, to the server, through the local loopback interface, is accepted.
## This will allow the server to talk to itself.  This may be required for some services, as well
## as for the server to access its own web server.

/sbin/iptables -A INPUT -p ALL -i lo -s $IP -j ACCEPT
## This adds a rule to the INPUT table for all protocols, going into the local interface
## and coming from $IP, which is the server's actual IP address.  All these packest are accepted.
## This is basically a continuation of the previous rule.

/sbin/iptables -A INPUT -p UDP -i eth0 --dport 67 --sport 68 -j DROP
## This adds a rule to the INPUT table, for all UDP packets going into interface eth0 with a 
## destination port of 67 and a source port of 68, to drop the packet.  These packets will be
## DHCP requests from the local network.  Since this server is not a DHCP server (the router
## does that) these packets are simply dropped.

/sbin/iptables -A INPUT -p ALL -d $IP -m state --state ESTABLISHED,RELATED -j ACCEPT
## This adds a rule to the INPUT table, for all protocols with a destination IP of $IP (the
## server's ip address.  The stateful packet engine is initialized (-m state) and the state is
## checked to see if it is ESTABLISHED or RELATED.  ESTABLISHED connections are connections that
## are already talking.  This way, any current, active connections (such as SSH) are only
## processed to this point before being accepted.  RELATED connections are connections that are
## spawned by other, existing connections.  For instance, FTP begins a connection on port 21,
## but then negotiates a data connection on some arbitrary, high port number.  This would allow that
## to work properly.

/sbin/iptables -A INPUT -p TCP -i eth0 -j tcp_packets
## This adds a rule to the INPUT table for TCP packets coming into eth0 to jump to the tcp_packets
## table.  Basically once the above rules are met, TCP packets (the most common packet to be
## expected on this server) are immediately sent to the tcp_packets table.  The less rules that
## a packet has to traverse, the lower the CPU overhead and the packet latency.

/sbin/iptables -A INPUT -p UDP -i eth0 -j udp_packets
## This adds a rule to the INPUT table for UDP packets coming into eth0 to jump to the udp_packets
## table.  UDP packets will be the second-most received packet type, so these are handled here.

/sbin/iptables -A INPUT -p ICMP -i eth0 -j icmp_packets
## This adds a rule to the INPUT table for ICMP packets coming into eth0 to go to the icmp_packets
## table.  ICMP packets are the last protocol we're going to be concerned with.  Any other
## protocols will be handled below.

/sbin/iptables -A INPUT -i eth0 -d 224.0.0.0/8 -j DROP
## This adds a rule to the INPUT table for packets going into eth0 with a destination IP address
## of 224.0.0.0/8 (-d) to be dropped.  Apparently Client for Microsoft Networks generates alot of
## traffic like this, and this rule simply catches and drops these packets before they're logged.
## 224.0.0.0/8 means 224.0.0.0 - 224.0.0.255...the /8 signifies 8 bits for the host portion and
## is just an alternate way of writing a subnet mask.  Alternately you could have written
## 224.0.0.0 255.255.255.0.

/sbin/iptables -A INPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "IPT INPUT packet died:"
## This adds a rule to the INPUT table, settinga  limit (-m limit), the limit being 3/minute
## (--limit), the initial limit being 3 (--limit_burst), to LOG the packet (-j LOG) with a
## loggging-level of DEBUG (--log-level DEBUG) prefixing the log entry with 
## 'IPT INPUT packet died:' (--log-prefix).  Basically, we're taking any packet that made it
## this far and logging it.  We're limiting it to 3 logs per minute to keep the logs from going
## insane.  The logs are appended to the system log (syslogd) and are readable with the dmesg
## command.

##
## Define the OUPUT table.  Here we're defining our OUTPUT table.  All packets outbound from our
## server to the network have to traverse these rules before being sent.
##

/sbin/iptables -A OUTPUT -p TCP -j bad_tcp_packets
## This appends a rule to the OUTPUT table, for all TCP packets, to jump to the bad_tcp_packets
## table.  Basically we're checking our outbound packets to make sure there isn't anything funny
## going on.

/sbin/iptables -A OUTPUT -p ALL -o eth0 -s $IP -j ACCEPT
## This appends a rule to the OUTPUT table, for all protocols going out of interface eth0 with a
## source address of $IP, to be accepted. Basically, if it's originating from our server, with 
## our server's IP address, it's accepted.

/sbin/iptables -A OUTPUT -p ALL -o lo -s 127.0.0.1 -j ACCEPT
## This appends a rule to the OUTPUT table, for all protocols going out of the local interface,
## with a source ip of 127.0.0.1 (the loopback address), to be accepted.  This is only a
## continuation of the previous rule.

/sbin/iptables -A OUTPUT -p ALL -o lo -s $IP -j ACCEPT 
## More of the same.  This allows packets from out local interface with our real IP to be sent
## out.
 
/sbin/iptables -A OUTPUT -m limit --limit 3/minute --limit-burst 3 -j LOG --log-level DEBUG --log-prefix "Illegal Output:" 
## This appends to the output table, a limit of 3/minute, starting at 3, to log it with a
## DEBUG level of logging and to prefix the log entry with 'Illegal Output:'.  Basically
## this is the same logging command we had on our INPUT table.  This logs any packets
## that don't match our OUTPUT accept rules and logs it to our system log (syslogd) with a prefix
## of 'Illegal Output:".  Since our Output rules are pretty broad, the only packets that made it
## this far would have a source ip address that weren't 127.0.0.1 or our $IP address.  Basically,
## if you have any logs here either I forgot something or somehow the server is trying to spoof
## its IP.

##
## Define the bad_tcp_packets table.  Here we're defining our bad_tcp_packets table, which
## basically pre-processes our TCP packets to make sure they're not doing anything wrong.
## A bad packet could denote a mistake or connection issue, but could also be something
## less innocent, such as a port-scan.

/sbin/iptables -A bad_tcp_packets -p tcp --tcp-flags SYN,ACK SYN,ACK -m state --state NEW -j REJECT --reject-with tcp-reset
## This appends to the bad_tcp_packets table, for all TCP packets, (--tcp-flags) with flags SYN
## and ACK set, with a state of NEW, to be REJECTed with a tcp-reset packet (--reject-with).
## First the reason: by standard, any new TCP connections must begin with a packet with just the
## SYN bit set.  This is the first part of the 3-way handshake.  This rule tests new, inbound
## connections to see if they have both SYN and ACK set, which would denote a non-new connection.
## If a packet does come in with the bits set wrong, we return a tcp-reset packet, which forces
## the host on the other side to reinitialize the 3-way handshake.  The --tcp-flags portion is a
## mask/match pattern.  Basically, the mask is SYN and ACK, while the match is SYN and ACK.  Thus,
## both SYN and ACK must be on to match the rule.  If we had simply used SYN,ACK SYN, then the SYN
## bit would have to be on and the ACK bit would have to be off.  Similarly, we could have had
## SYN,ACK,FIN SYN,FIN and both SYN and FIN would have to be on, while ACK would have to be off.
## Read up on TCP packet structure for more information about packet flags.

/sbin/iptables -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j LOG --log-prefix "New not syn:"
## This appends to the bad_tcp_packets rule, for TCP packets, that do NOT have the syn bit set
## with the ACK and FIN bits cleared and are new, to log them with the "New not syn" prefix.
## Note the ! which inverses the following rule, which is --syn.  Basically this logs any new 
## packets which do not have SYN on with ACK and FIN cleared.  SYN on with ACK and FIN cleared
## is the packet structure that initializes a three-way handshake.  This just logs those.
## So, why do we have the previous rule?  The reason is that the SYN/ACK set typically means a 
## computer believes that it has an active connection, when it does not.  This could happen for 
## many legitimate reasons, and is thus not logged. 
 
/sbin/iptables -A bad_tcp_packets -p tcp ! --syn -m state --state NEW -j DROP
## This appends to the bad_tcp_packets table, for TCP packets that do NOT have the syn bit set
## with the ACK and FIN bits cleared and are new, to be dropped.  This continues on from the
## previous rule, and just drops the packets after the previous rule logs them.

##
## Define allowed table.  Here we're defining our allowed packets table.  This is basically some
## final processing before we allow a packet to be accepted.
##

/sbin/iptables -A allowed -p TCP --syn -j ACCEPT
## This appends to the allowed table, for all TCP packets that have SYN set with ACK and FIN
## bits cleared, to be allowed.  This allows new connections.

/sbin/iptables -A allowed -p TCP -m state --state ESTABLISHED,RELATED -j ACCEPT
## This appends to the allowed table, for all TCP packets in the ESTABLISHED,RELATED state, to
## be accepted.  Basically, any existing connections that make it this far are accepted.  We
## actually already have this rule in our INPUT table, so this is largely redundant, but the
## firewall script this was based on had it, so I decided to leave it as well.

/sbin/iptables -A allowed -p TCP -j DROP
## This appends to the allowed tale, for all TCP packets to be dropped.  Basically anything that
## isn't a new connection or an established/related connections will be dropped.

##
## Define the tcp_packets table.  Here we do all our TCP processing.  A tcp packet will have made
## it through our bad_tcp_packets table, so now we're just defining what we're letting in and
## what we're killing.
##

/sbin/iptables -A tcp_packets -p TCP -s 0/0 --dport 80 -j allowed
## This appends to the tcp_packets table, for TCP packets with a source of anything (-s 0/0) and a
## destination port of 80, to jump to the 'allowed' table.  Basically we're making all traffic
## that's going to our web server (port 80) jump to the allowed table for final processing.  The
## source of 0/0 is again ip and subnet.  This would be equivalent to 0.0.0.0 0.0.0.0.

/sbin/iptables -A tcp_packets -p TCP -s 0/0 --dport 22 -j allowed
## This appents to the tcp_packets table, for all TCP packet, with a source of anything and a
## destination port of 22 to jump to the allowed table. This is the same as above, but for port
## 22, which is our SSH port.

/sbin/iptables -A tcp_packets -p TCP -j DROP
##  This appends to the tcp_packets table, for all TCP packets, to be dropped.  This kills
## all packets not destined for ports 22 or 80.

##
## Define our UDP_packets table.  Here we're defining our rules for any UDP packets.
##

/sbin/iptables -A udp_packets -p UDP -s 0/0 -j DROP
## Append to udp_packets table, for all UDP packets, from all sources, to be dropped.  We're not
## allowing any UDP packets at this time.  However, the table exists, so if I want to allow
## something at a later date I can.

##
## Define our ICMP_packets table.  Here we define our rules for any ICMP packets.
##

/sbin/iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 8 -j ACCEPT
## This appends to the icmp_packets table, for all ICMP packets, from anywhere and a type of 8
## (--icmp-type) to be accepted.  Type 8 is echo reply, which is used by ping.  This basically
## allows hosts to ping me.

/sbin/iptables -A icmp_packets -p ICMP -s 0/0 --icmp-type 11 -j ACCEPT
## This appends to the icmp_packets table, for all ICMP packets from all source IP addresses and a
## type of 11 to be accepted.  This allows ICMP type 11, which is "time exceeded".  If a 
## host/gateway either has ttl hit 0 or is unable to assemble a fragmented packet, it sends this
## packet.  This allows the packet to be received.

/sbin/iptables -A icmp_packets -p ICMP -j DROP
## This appends to the icmp_packets table,f or all ICMP packets, to be dropped.  Basically all
## remaining ICMP packets are now dropped.
]
Comments (0)