Howtos Basic IPTables
From 5dollarwhitebox.org Media Wiki
Contents |
Summary
Alot of people are freaked out by IPTables and find it hard to understand. However, once you get the grasp of it the basics are easy. This document will serve as a basic how-to on using iptables. I am in no way an iptables guru, but have been using it like this for quite a while. If I've made any mistakes please don't hesitate to email me.
- Author: BJ Dierkes
- Last Updated: December 16th, 2005
- Contact: wdierkes [at] 5dollarwhitebox [dot] org
The System
- Debian Sarge 3.1
- Vanilla 2.6.12.4 kernel from mirrors.kernel.org
- iptables administration utility version 1.2.11-10
Preparation
This How-To is performed on a Debian Sarge 3.1 box, though the commands and syntax should work for any linux distro. Before you can configure iptables, you first must ensure that it has been compiled into the kernel, and that you have the proper userland utilities installed.
You should have a config file from when the kernel was compiled. Grep'ing it for "CONFIG_IP_NF" should produce '=y' or '=m' for most of the lines/options. Here you see that "CONFIG_IP_NF_IPTABLES" was compiled as a kernel module.
# cat /boot/config-2.6.12.4 | grep -i "CONFIG_IP_NF" CONFIG_IP_NF_CONNTRACK=m CONFIG_IP_NF_FTP=m CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=m CONFIG_IP_NF_MATCH_LIMIT=m CONFIG_IP_NF_MATCH_MAC=m CONFIG_IP_NF_MATCH_PKTTYPE=m CONFIG_IP_NF_MATCH_MARK=m CONFIG_IP_NF_MATCH_MULTIPORT=m CONFIG_IP_NF_MATCH_TOS=m CONFIG_IP_NF_MATCH_RECENT=m CONFIG_IP_NF_MATCH_ECN=m CONFIG_IP_NF_MATCH_DSCP=m CONFIG_IP_NF_MATCH_AH_ESP=m CONFIG_IP_NF_MATCH_LENGTH=m CONFIG_IP_NF_MATCH_TTL=m CONFIG_IP_NF_MATCH_TCPMSS=m CONFIG_IP_NF_MATCH_HELPER=m CONFIG_IP_NF_MATCH_STATE=m CONFIG_IP_NF_MATCH_CONNTRACK=m CONFIG_IP_NF_MATCH_UNCLEAN=m CONFIG_IP_NF_MATCH_OWNER=m CONFIG_IP_NF_FILTER=m CONFIG_IP_NF_TARGET_REJECT=m CONFIG_IP_NF_TARGET_MIRROR=m CONFIG_IP_NF_NAT=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=m CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_SNMP_BASIC=m CONFIG_IP_NF_NAT_IRC=m CONFIG_IP_NF_NAT_FTP=m CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_MANGLE=m CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m CONFIG_IP_NF_TARGET_DSCP=m CONFIG_IP_NF_TARGET_MARK=m CONFIG_IP_NF_TARGET_LOG=m CONFIG_IP_NF_TARGET_ULOG=m CONFIG_IP_NF_TARGET_TCPMSS=m CONFIG_IP_NF_ARPTABLES=m CONFIG_IP_NF_ARPFILTER=m CONFIG_IP_NF_ARP_MANGLE=m CONFIG_IP_NF_COMPAT_IPCHAINS=m CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_COMPAT_IPFWADM=m CONFIG_IP_NF_NAT_NEEDED=y
This isn't all that necessary, since you'll find out real quick whether iptables works or not once we try to add some rules.
You can check whether you have the iptables administration utility installed by executing:
# dpkg -l iptables iptables 1.2.11-10 Linux kernel 2.4+ iptables administration to
...or for rpm based distro:
# rpm -qa | grep iptables
...or you can just see if the binary is there!
# which iptables /sbin/iptables
If the utility is missing you can install it like so:
Apt
# apt-get update && apt-get install iptables
RPM
# rpm -Uvh iptables-xxxx.rpm Preparing ################################# [100%]
Up2date/Yum
# up2date -u iptables # yum install iptables
The Main Files
Debian
- /etc/init.d/iptables – INIT script to start|stop|restart the service (and save rulesets). This file is no longer default as of Sarge but you can still get it (I'll show you).
- /var/lib/iptables – Debian's home for the 'active' and 'inactive' iptables-save counter files (i.e. The saved rulesets).
- /var/lib/iptables/active – Active Counters (more on that later)
- /var/lib/iptables/inactive – Inactive Counters
- /sbin/iptables – The administration utility/binary.
RedHat
- /etc/init.d/iptables – INIT script to start|stop|restart the service (and save rulesets).
- /etc/sysconfig/iptables – RedHat's file for the iptables-save counter files (i.e. The saved rulesets).
- /sbin/iptables – The administration utility/binary.
A Little About IPTables
To see what rulesets we currently have in place, execute:
# iptables --list Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
This is what you will see when there are no rule sets in place. Looking at this we see 3 'Chains'.
- INPUT - Holds rules for traffic directed at this server.
- FORWARD – Holds rules for traffic that will be forwarding on to an IP behind this server (i.e. If this box serves as a firewall for other servers).
- OUTPUT – Holds rules for traffic that is coming from this server out to the internet.
Mainly we will be dealing with traffic directed at this server, and will be issuing rules for the INPUT Chain. When traffic passes through the kernel, it determines a “TARGET” based on whether the packet matches a rule or not. General targets are:
- ACCEPT – Traffic is accepted for delivery.
- REJECT – Traffic is rejected, sending a packet back to the sending host.
- DROP - The traffic is dropped. Nothing is sent back to the sending host.
Configuring Rule Sets
So, lets get down to it. Its important to note that the order in which rules are appended is very important. For example, if your first rule is to deny everything... then no matter what you specifically allow, it will be denied.
Also to note is that nothing you do is saved on disk until you execute 'iptables-save' (or use the init script to save). All counters/rulesets are in memory. Once the server reboots, or you execute 'iptables --flush' everything you've worked on is gone. Personally I work out of a bash script file called 'iptables-rules.sh', which allows me to keep everything organized and commented. If I make a mistake, I have no worries if I just want to flush all the rules out, I just go right back to my bash script and start editing again, save it out and execute the script (this however will not run at startup... that will be covered in the next section).
First Things First
Its very important that if you are working on this server remotely through ssh, that you make every effort to not lock yourself out. Therefore, our first rule will be to ensure that no matter what, I can still access ssh from my IP address.
# iptables -A INPUT -s 192.168.1.10 -d 10.1.15.1 -p tcp --dport 22 -j ACCEPT
Lets break that down:
- -A => Tells iptables to 'append' this rule to the INPUT Chain
- -s => Source Address. This rule only pertains to traffic coming FROM this IP. Substitute with the IP address you are SSHing from.
- -d => Destination Address. This rule only pertains to traffic going TO this IP. Substitute with the IP of this server.
- -p => Protocol. Specifying traffic which is TCP.
- --dport => Destination Port. Specifying traffic which is for TCP Port 22 (SSH)
- -j => Jump. If everything in this rule matches then 'jump' to ACCEPT
Next, we will want to use some standard rules for general network traffic. This goes a bit beyond the basic stuff, however iptables can determine the 'state' that a packet is in. This has to do with standard TCP communication. For example, the 3 way handshake between two hosts when transmitting data.
- NEW => Server1 connects to Server2 issuing a SYN (Synchronize) packet.
- RELATED => Server 2 receives the SYN packet, and then responds with a SYN-ACK (Synchronize Acknowledgment) packet.
- ESTABLISHED => Server 1 receives the SYN-ACK packet and then responds with the final ACK (Acknowledgment) packet.
After this 3 way handshake is complete, the traffic is now ESTABLISHED. In order for this type of TCP communication, something similar to these three rules are necessary:
# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # iptables -A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT # iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
The last rule obviously allows any traffic the leave the server.
Now that we have our basics set in place, lets see what iptables lists for our rulesets:
# iptables --list Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT tcp -- 192.168.1.10 10.1.15.1 tcp dpt:ssh ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED Chain FORWARD (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state NEW,RELATED,ESTABLISHED
Standard Examples
From here you can add whatever rules you like. If your running a basic webserver, you'll probably need some rules similar to:
Individual Rejects/Drops First
BAD GUYS (Block Source IP Address): # iptables -A INPUT -s 172.34.5.8 -j DROP SPAM IS FOR PUSSIES (notice the use of FQDN): # iptables -A INPUT -s mail.spammer.org -d 10.1.15.1 -p tcp --dport 25 -j REJECT
Then Open It Up
MYSQL (Allow Remote Access To Particular IP): # iptables -A INPUT -s 172.50.3.45 -d 10.1.15.1 -p tcp --dport 3306 -j ACCEPT SSH: # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 22 -j ACCEPT Sendmail/Postfix: # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 25 -j ACCEPT FTP: (Notice how you can specify a range of ports 20-21) # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 20:21 -j ACCEPT Passive FTP Ports Maybe: (Again, specifying ports 50000 through 50050 in one rule) # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 50000:50050 -j ACCEPT HTTP/Apache # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 80 -j ACCEPT SSL/Apache # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 443 -j ACCEPT IMAP # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 143 -j ACCEPT IMAPS # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 993 -j ACCEPT POP3 # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 110 -j ACCEPT POP3S # iptables -A INPUT -d 10.1.15.1 -p tcp --dport 995 -j ACCEPT Any Traffic From Localhost: # iptables -A INPUT -d 10.1.15.1 -s 127.0.0.1 -j ACCEPT ICMP/Ping: # iptables -A INPUT -d 10.1.15.1 -p icmp -j ACCEPT
Global Rejects Last
Reject everything else to that IP: # iptables -A INPUT -d 10.1.15.1 -j REJECT Or, reject everything else coming through to any IP: # iptables -A INPUT -j REJECT # iptables -A FORWARD -j REJECT
Notice the we do the global REJECT lines last! These must be last.
Saving Rule Sets
With the init scripts, saving rule sets is quite easy. Once you are happy with your config, just do one of the following:
The Debian Way
The old style init script is no longer in Sarge by default, but it is still around for legacy use. I believe the new way is to use ' /etc/network/if-up.d' and '/etc/network/if-down.d' for iptables scripts (but I don't like that).
You can grab the legacy INIT script this way:
# gunzip /usr/share/doc/iptables/examples/oldinitdscript.gz -c > /etc/init.d/iptables # chmod +x /etc/init.d/iptables # mkdir /var/lib/iptables # chmod 700 /var/lib/iptables
Now that you have the script in place you can do the needful.
Active Rules
The Active rules are those loaded when starting iptables:
# /etc/init.d/iptables save active Saving iptables ruleset: save "active" with counters.
This saves your rules in /var/lib/iptables/active
Inactive Rules
You can also configure a second set of rules for when you stop iptables called 'inactive'. Iptables doesn't actually “stop”, it just flushes out the rule sets that are in place and then loads the 'inactive' rules.
# /etc/init.d/iptables stop Loading iptables ruleset: load "inactive"
Therefore, you can set your 'inactive' rules, and then save them with:
# /etc/init.d/iptables save inactive Saving iptables ruleset: save "inactive" with counters.
The RedHat Way
The RedHat INIT script is very similar. You can use it to start and stop iptables, as well as save rule sets.
To save your active rules execute the following:
# /etc/init.d/iptables save
This will save your rules to '/etc/sysconfig/iptables'.
When you start iptables, the rules are read from '/etc/sysconfig/iptables':
# /etc/init.d/iptables start Starting iptables [OK]
And when you stop iptables, all rules are flushed:
# /etc/init.d/iptables stop Stopping iptables [OK]
Manual Save and Restore
You can also manually use the iptables-save and iptables-restore utilities like so:
Save the rules to a file
# iptables-save > /root/iptables-save.out
Restore the rules
# iptables-restore -c /root/iptables-save.out
The -c tells iptables-restore that this is file was created using iptables-save, which outputs the rules as “counters”.
Conclusion
And there you go, iptables at its very basic. The uses of iptables are too numerous to even start truly doing a howto on them. However, for basic security and understanding of IPTables, I hope this might have helped you. If there is anything I could add, please feel free to email me.
Tips And Tricks
Port Redirects
Suppose you'd like to accommodate customers that aren't able to connect to port 25 through there ISP. This will redirect any traffic going to IP 10.1.1.1 (port 26) and send it to IP 10.1.1.1 (port 25):
iptables -A PREROUTING -p tcp -m tcp -d 10.1.1.1 --dport 26 -j DNAT --to 10.1.1.1:25
OR you might need to do:
iptables -t nat -A PREROUTING -d 10.1.1.1 -p tcp --dport 26 -j REDIRECT --to-ports 25
NAT Masquerade
iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -d ! 10.10.10.0/24 -j MASQUERADE sysctl -w net.ipv4.ip_forward=1
Where 10.10.10.0 is the network you are masquerading for.
Resources
- Netfilter/Iptables: http://www.netfilter.org/
- Transmittion Control Protocol: http://www.rhyshaden.com/tcp.htm
