IPTables HOWTO Matt Wright Matt Wright Consulting
matt@consultmatt.co.uk
2001-11-21 v0.1 2001-11-21 mww Initial writing began. This document describes the main functions of the Netfilter Packet filter (IPTables) included in the 2.4.x series kernels.
Introduction I felt the need to write this HOWTO because of, what I thought, is the poor level of documentation on implementing Packet Filtering firewalls using the 2.4.x Netfilter packet filter. The HOWTO covers using native IPTables commands (ie. not using the ipchains.o) to implement a packet-filter based firewall and the various supported types of NAT. Copyright and License This document is Copyright 2001 by Matt Wright. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is available at http://www.gnu.org/copyleft/fdl.html Send feedback to matt@consultmatt.co.uk. About the author My name is Matt Wright. I'm 16 year-old student in Blackburn, Lancashire. I'm a freelance Linux consultant. I am the proud owner of a Duron 950Mhz (all I could easily afford) with 256MB SDRAM, Voodoo 4 Video Card, ATI All-in-Wonder Pro Video Card. I also have a 266Mhz Cyrix that runs my USB ADSL connection, of which if you are reading this from http://www.consultmatt.co.uk you will be using. You can find me at www.consultmatt.co.uk. Or at matt@consultmatt.co.uk. Acknowledgements TODO: Insert greetz here What is IPTables IPtables (known as Netfilter) was written by Paul Russell and the other members of the Netfiler Project Team. It was meant as a replacement for IPChains that was implemented in the 2.2.x series kernels. It offers true 1:1 NAT capabilities, Packet filtering and connection tracking. One major upshot of this is that due to the implementation of connection tracking you can allow incoming connections by whether or not they relate to an established connection. There is still some need for helper modules for some connection types. (FTP and IRC at the moment) Requirements You only need a couple of things to get IPTables going, these include: A 2.4.x series kernel with the Netfilter modules compiled. (I will deal with the Netfilter code as modules but feel free to compile them in and ignore the module information.) The IPTables source code, get it from The Netfilter Project This HOWTO does not cover compiling and/or installing IPTables. Usually this is pre-installed with a 2.4.x distro and if not then please consult the Netfilter website for more information. Basic knowledge about networking; ports, packets, etc. Essential IPTables commands IPTables has a veritable feast of switches and parameters so this section covers the most useful and most used of IPTables' switches. They are listed below: -t <table>: This specifies the table to work on. If -t is ommited then the "filter" table is specified. -L <chain>: List all rules in the specified chain. If the chain is not specified it lists all chains and rules in the current table. -F <chain>: Flushes the specified chain of all rules. Again, if no chain is specified it flushes all rules in all chains in the current table. -X <chain>: This removes the specified user-defined chain. If no chain is specified it deletes all user-defined chains in the current table. (Note: You cannot delete a chain referenced to by another rule.) -N <chain>: This creates a new user-defined chain for you to add rules to. -A <chain> <rule>: This appends a rule to the end of the specified chain. Rules are explained later. -D <chain> <number>: Deletes the rule at position "number" in the specified chain. -P <chain> <policy>: Changes the policy for "chain" to "policy". That is the main commands outlined, the rest of the commands are well documented in the man page IPTABLES(8). It also contains the flags for useage in rules. I won't list them here because there are too many. Tables, Chains and the like There are two main definitons that need to be set out here. The first is a table. Tables contain a set of chains, either built-in or user-defined. The main two tables you will encounter are the "filter" table and the "nat" table. Chains are lists of rules that a packet traverses. When a packet enters a chain the packet is checked against each criteria, if it is met then the packet's fate is determined by the "target" flag. (Explained later in detail). The Filter Table I am going to explain each table and chain before I show a diagram of the overall system. This is so you can understand what each part does without having to refer back to this section while looking at the diagram. The first table we meet is the filter table. This is the table you encounter if you type iptables -L (-L means list). If you actually enter this command you will encounter a display similar to this: [root@enterprise matt]# iptables -L 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 The INPUT chain We'll start with the INPUT chain first. When packets enter the system they are checked for routing, if the packet is inbound to the local machine (in this case to enterprise) then the packet is sent down the INPUT chain. In its current state the chain is wide open. This is due to the policy. When the Tables are initalised each policy is set to ACCEPT, the policy defines what happens when a packet meets none of the rules in the chain. To use an analogy it is what happens if it drops off the end of the chain. The case in question has the policy ACCEPT. This is in fact a target that can be used in a rule, so as not to repeat myself targets are explain in a later section. The INPUT chain is the chain that you will most want to secure on your machine. This is the rule to use to block (or open) ports on the local machine. Anything accepted in the chain will make it to your network server daemons, anything dropped will not. The FORWARD chain The FORWARD chain is also an important chain, especially if you plan on masquerading or NAT'ing your conenctions. As with the INPUT chain the packets appear here after routing but when the routing specifies that the packet is bound for a machine on the network other than itself. For instance, if you are using Masquerading and a incoming packet from the internet enters the network interface the packet would be processed by the routing information and enter the FORWARD chain as it is bound for another machine. If the packet is accepted (or is accpeted by policy) then it proceeds to the destination (and possibly into its INPUT chain if its running Linux), if however it is dropped then it proceeds no further and it is dumped into the nearest blackhole. The OUTPUT chain The OUTPUT chain is the final built-in chain in the filter table. It governs the outgoing packets once they have been transmitted into the network layer by the computer daemons. As with the other chains anything accepted will be allowed passage out to the big-wide-world and dropped packets appear alongside their rejected brothers (or sisters). The NAT table The NAT (Network Address Translation) table is not accessible by default. Firstly, if you have the netfilter code compiled as modules then you may have to do a modprobe iptable_nat. Secondly to access any of the chains in the NAT table iptables must be invoked with the -t nat option. Eg: iptables -t nat -L This table is the other super-handy table that we will use. All packets traverse the chains in here before entering the filter table and before the packets from the filter table leave the computer. I think a little more explanation here is in order. The typical default NAT tables output is listed below: [root@enterprise matt]# iptables -t nat -L Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination I shall concentrate on the PREROUTING and POSTROUTING chains in this table (as I'm not yet sure on what the OUTPUT is for, please mail me if you can help). The PREROUTING chain The PREROUTING chain....you remember where I said before that all the packets are routed then enter the FORWARD/INPUT/OUTPUT chains?? Well the PREROUTING chain is where the packets traverse BEFORE they get routed. If for instance you wanted to make all packets destined for port 80 on the local machine (10.0.0.1) actually appear on port 81 of 10.0.0.2 then you would insert the DNAT rule here. This is also the best place to check for simple spoofing, things like local, private IP addresses (10.0.0.x, 192.0.0.x, etc) appearing on the internet side of your machine are obviously wrong and can be dropped quicker than you can say "distributed denial-of-service attack". Finally, this is the ONLY place that incoming NAT (Destination NAT, DNAT) can be performed. This is so the packets can be mangled to force then down the FORWARD chain instead of the INPUT where they would be lost. The POSTROUTING chain This chain is also very important (else why would I mention it!!) it governs the handling of packets after they have been routed and are about to be spat out of an network adapter. The major use for this chain is to allow IP masquerading or Source NAT. There is a slight difference. IP Masquerading is made specially for all us people with Dynamic IP address. When the interface is taken down the IP Masq tries to make sure all connections are closed, this is logical is it is unlikely you will have the same IP when the adapter comes up again. Source NAT is different, it leave ports open. This is made for Static IP based conenctions, if for some reason your interface dies then when it goes live again it will have to same IP. So, if there have been no timeouts and all applications still _assume_ they are connected they carry on as usual. The Diagram!! ________ _____ _________ Incoming / \ / \ / \ Outgoing -->|PREROUTING|--->|FORWARD|-------|POSTROUTING|-----> \________/ \_____/ \_________/ | | v ____ ___ / \ / \ |OUTPUT| |INPUT| \____/ \___/ ^ | | -------> Local Process --------> Packet Filtering This is where you find out how to firewall off you local machine. It will involved some of the theory from above to I adive reading it before proceeding. Target (-j) ACCEPT,DROP,REJECT,etc When I was talking above about accepting, dropping and the like I wasn't just using a phrase. The -j flag in rules specifies what target the rule has, in layman speak (I know I needed it) it's what happens when the packet matches the rule concerned. If you had the following command: iptables -A INPUT -p tcp --dport 80 -j ACCEPT This would instruct any packet that has made it to that rule and that is on port 80 to be accepted. Target: ACCEPT This is what is says, it allows a matching packet to continue unhindered. Also, once a packet has been accpeted it no longer traverses the chain. So if the above chain allows a packet it is universally allowed. A moral is in this tale!! If you have any mission critical filters to be tested on all packets before any are allowed then put them at the top of the chain Target: DROP This is the exact opposite of ACCEPT, if the packet matches a filter that targets to a DROP then the packet is dumped into oblivion and is never seen again. Please beware, DROP is a stealth DROP. If a packet is DROPed then NO response is returned to say it failed, you program will just sit around till it times out. Target: REJECT This is similar to DROP, firstly in the netfilter code it is created as a seperate module (ipt_REJECT.o) and as such needs to be at the very least compiled if not modprobe'd. Compared to DROP the only difference it a REJECTed packet has a response sent to the originator saying that it failed. I tend to use DROP as its stealthy but REJECT has its uses. Default Policies Policies, Policies!! This could be a major security hole on you machine. The default policies come set to ACCEPT andif you've read the above stuff then you will find that this means ANY packet can get in, out or through your network. The most secure action to take is to set all policies to DROP, this has its problems. Firstly, you can't get in to you machine, soo if like me you administer your box via SSH you've just cut yourself off. Secondly, no one can get out either, so the machine itself is unable to get on the internet. Yes, you can't get through either, if your DROPing all your packets you can't forward them as well. To change policies you would do the following: iptables -P INPUT DROP If you are making a ruleset for running at startup then you may want to policiy all of these off. However, if you are experimenting I suggest caution (or at least to use a local console). Matching by Protocol (Ports, etc) In IPTables, if you examine the man page, there is a switch called -p, --protocol [!] <protocol> this allows you to specify rule matches against the protocol. An extension that is provided by suppliing a -p tag allows matching of ports. The two flags --source-port and --destination-port (these can aliased to --sport and --dport) they are mainly used in to different ways. The --source-port can be used anywhere, however, this matches packets based on the port of the orgininating machine. So if this is matched on the INPUT chain a --sport would match the port on the remote machine. In this sense it is more useful in the OUTPUT chains as the source in this case is the local machine. --sport would allow you to match say all outgoing port 80 transmissions to allow you webserver to operate if you've change the OUTPUT policy. The --destination-port can be used in the opposite way, allowing you to match the port to which the packet is destined to go to. So on the INPUT chain it matches the local port while on the OUTPUT chain it matches the remote port. So then, to allow traffic into your machien via the input filter you could match packets destined for port 80 on your local machine and ACCEPT them. Syntax: -p [!] <protocol>: Protocol is reqiured. Can be a builtin (such as www, ftp, etc), port number or any service from /etc/services. ! can be specified to negate the parameter, or more easily put using ! will watch everything but the protocol. --sport [!] <port/range>: The port or range must be specified. The port can be expressed as a number (eg. 80), a service name (eg. www, ftp, etc) or a range in the form start:end (eg. 80:110). Again th ! will negate the selection matching the opposite of what was specified. --dport [!] <port/range>: The port or range must be specified. The port can be expressed as a number (eg. 80), a service name (eg. www, ftp, etc) or a range in the form start:end (eg. 80:110). Again th ! will negate the selection matching the opposite of what was specified. Matching by Source IP and Destination IP Another useful filter is to be able to filter the connections by their Source IP, Destination IP, both or ranges. To put a practical side on it, this enables us to test for easy spoofing checks, allow any machine on our internet networks different access than that of an internet client. This is achieved by two commands, the -s (for source IP) and -d (for Destination IP). As with the port matching the INPUT and OUTPUT have different definitions of destination and source. In the INPUT chain the source refers to the remtoe machine and the destination refers to the local machine. Of course, in the OUTPUT chain the source is the local machine and the destination is the remote machine. Syntax: -s [!] <IP Address>: IP Address is required, can be expressed as a dotted decimal IP Address (eg. 10.0.0.1) or an IP Class (or classless) range (eg. 10.0.0.0/16). -d [!] <IP Address>: IP Address is required, can be expressed as a dotted decimal IP Address (eg. 10.0.0.1) or an IP Class (or classless) range (eg. 10.0.0.0/16). Adapter Matching A very, very useful two switches here. The two switches in this section allow you to make a rule match a particular adapter. Say you have an eth0 (local network) and a ppp0 (internet). You could force Masq request to come only from your internal adapter. The switches are: -i <adapter>: This switch matches the incoming adapter. Use it in the INPUT, PREROUTING tables to match where the packet has come in from. -o <adapter>: This switch matches the outgoing adapter. Use it in the OUTPUT and POSTROUTING tables to match the adapter the packet will go out through. Connection Tracking and States Final bit of info before I tell you how to set up a good firewall (at least I think it's good). Connection tracking is a friend and a foe to your nice secure firewall. It allows the Netfilter code to detect which packets are for which machine and allows full 1:1 NAT. The states (I think) sort of merge into the same area. They allow you to set rules to match by the TCP connection state. Put more usefully; State checking also you to drop packets that are not part of an already established connection, or to drop new connections not originating from your network (use it in Masq'ing). There are four main states: INVALID, when the packet is not related to any connection. NEW, a packet that is attempting to create a new connection. ESTABLISHED, a packet that is part of an already established TCP conversation. RELEATED, when a packet is starting a new connection but is in some way related to an existing connection. These are extremely useful for only allowing NEW Masq connections out from the internal network or to allow create connections in and out of the INPUT chain. To use them you have to specify the -m state --state switches. The -m state tells IPTables to use the state checking module and then the --state allows you to supply states. I'll come back to using states when I explain the parts you need to your firewall. Now to try and design a firewall This is where all that reading will hopefully come in useful. This won't tell you the exact commands to type in but it should give you an idea on how arrange you rulesets and how things tie together. What do you need in a firewall? Why do you want a firewall? With the rise in broadband connecitons with more permanent IP address (not always static though) it is much easier to conduct attacks on certain people as the IP's stay pointing to the same machine for longer. Do you run a webserver? Do you want to stop any chance of easily hacking you new Linux box? In which case this is the right place to be. Note: A firewall CANNOT stop all attacks, nor can it stop people with valid passwords from gaining entry and trying to find weaknesses. Note before you start A note about rc.firewall On most RedHat derived distributions there is the /etc/rc.d . In here there is usually a rc.firewall. This is executed at startup, so when you have got a good rule/ruleset add the iptables commands to this and it will run whenever you reboot. A note about IP Forwarding The IP Forwarding code (known as Masquerading or NAT) is enabled by setting the file at /proc/sys/net/ipv4/ip_forward to contain a 1. Be warned: I have had trouble with getting Linux to enable this value in the rc.firewall so you may have to add it to a SysV init script to get it to work. Sealing you machine I work on the principle of making it airtight (ie. nothing allowed in and nothing allowed out) and then open up the ports we need. To seal the machine off the best way is to reset all the policies to DROP. In that way nothing works (you need to be sat at the console to do this) and nothign can get in. To seal off the policies use this command: iptables -P INPUT DROP iptables -t nat -P PREROUTING DROP This shows one policy set on the filter table and one on the NAT table, you would need to set each three chains on each table following that style to secure the machine. Opening ports for incoming connections Now that you have blocked all access into your computer we need to let some people back in. This is done by specifically allowing ports to be opened. Out of ease I usually leave the OUTPUT chain open so once you've opened ports you should see soem immediate action when you try and open a connection, say to test your web server. The following commands are used to open a port, or in-fact close on if you specify DROP. iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p udp --dport 53 -j DROP In the above examples, the first one matches any TCP port 80 connections (you _must_ specify a protocol if you want to use a port. Legal protocols are tcp, udp, icmp.) The second command matches any UDP based DNS traffic (port 53) and DROPs it. All the type of matching commands can be combined with source and destination IP checking or state checking or any other match criteria you can have due to your module configuration.