########################################################################################## ## ## ## 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.]
IP Tables
29 Nov 2004 @ 02:28PM
Updated: 27 Jan 2010 @ 03:20PM
Comments (0)