IPTables Tutorial Part 1 Linux comes with a powerful firewall built into it, although the interface to it is not entirely intuitive. This is a multi-part series in which I will go over some of the basic and not-so-basic uses of IPtables to set up a firewall for your home network. Today, we are going to consider the simplest case, a single workstation or simple server connected directly to the internet. Most home users are in this situation, or a similar one. If you are behind a router, then this situation will apply to the computer that receives incoming connections by default. Only one machine behind the router can have this capability, or incoming connections can be dropped altogether by default. By the end of this series it may make sense for you to set up the router to default all incoming connections to a particular machine, because IPtables gives you much more control and flexability than your router probably does. The IPTables filter table, which we will be most concerned with today, comprises of three built-in chains. The three chains are INPUT, OUTPUT, and FORWARD. Packets passing through the firewall are directed through one of these chains depending on the source and destination of the packets. Packets originating from outside the firewall and destined for the machine are passed through the INPUT chain. Packets originating from inside the firewall and destined for the outside pass through the OUTPUT chain. Packets which are being routed pass through the FILTER chain. Now let's look at the iptables interface very quickly. iptables is a userspace tool to add and remove rules to the kernel-level firewall. It needs to be called every time you want to add a rule, so it makes the most sense to create a shell script with all of your rules in it and have it run on startup. Lets start creating a simple firewall script. First, you are going to need the necessary kernel support for iptables to work. if you have firewall support compiled directly into your kernel, or if your kernel supports automatic module loading, then iptables will work out of the box. If not, you may have to load the necessary modules yourself, manually or in a startup script. These lines will load very basic firewall support for you, at least enough to get by for today: modprobe x_tables modprobe ip_tables modprobe iptable_filter modprobe xt_tcpudp modprobe nf_conntrack modprobe xt_state modprobe nf_conntrack_ipv4 Now, lets get root access and see where our iptables binary is stored: whereis iptables So the first line of our script should define where iptables is. This is so that we can give our script to others and they will only have to change this line to get it to work on their machines: IPT=/sbin/iptables We are going to want to make a blank slate for our firewall, so we are not adding rules on top of rules already working in the kernel. To flush the tables completely, we use the line: $IPT -F Now we are ready to set up our default policies. This means we are going to tell iptables what to do with a packet that doesn't match any other rule along the chain. Lets deal with out output chain first. Outgoing connections should be allowed because we have to assume that if you are initiating a connection, you approve of that connection, and the firewall should leave it alone. Therefore, we are going to have a default policy of accept. The syntax for this is: $IPT -P OUPUT ACCEPT Incoming connections are another story entirely. We don't want our box to accept any old connection request from anywhere on the internet. So the default policy for the INPUT chain is: $IPT -P INPUT DROP We are going to allow specific types of connections later when we add rules to the chain. For now, we can also set the Forward chain's policy to DROP: $IPT -P FORWARD DROP Now, we are going to add rules on the INPUT chain to make some types of incoming connections OK. For instance, we want all loopback traffic allowed. This is so we can access our own services even if we don't want people on the internet to use them. So this will be our first rule: $IPT -A INPUT --in-interface lo -j ACCEPT The -A INPUT switch means to append this rule to the INPUT chain. It is worth noting now that the order of the rules does matter, so you need to plan the logic of your scripts accordingly. The --in-interface lo switch sets this rule to match packets that are received on the lo device, and lo is of course the loopback device. -j switch is the target of the rule, and in this case we simply want to ACCEPT the packet. In simple terms, this rule will allow all packets originating from your own computer, so you can access your print local services, like your print server. Now we are going to open up specific ports to the internet. We do not, for instance, want internet connections to access out print server, but we may want them to access our web server. To see what services we have running on our machine and what ports they are using, we can use: netstat --inet -pln As we can see, we have our web server running on the non-standard tcp port 8008. To open this port up to internet traffic, we use the following line: $IPT -A INPUT -p tcp --dport 8008 -j ACCEPT This means we will append this rule to the input chain, match this rule to the tcp protocol, and match this rule to packets destined for port 8008 on our machine, which is the web server. These connections will be accepted, even though our default policy for the input chain is drop. Let's make another one of these rules to allow services in, let's say we want to allow SSH traffic so we can log in to our box over the internet. The line for that is simply: $IPT -A INPUT -p tcp -dport 22 -j ACCEPT This of course will only work if our ssh service is running on the standard port 22, which we should confirm with netstat. A list of default ports for standard services can be easily found using google. Finally, there's one more extremely important rule we must add at the end of our input chain. That is the rule to allow responses from connections that we initiated. For instance, if we use our browser to visit a website, we want to allow the website we asked for come through the firewall. Lets see what will happen if we don't have this rule set up... first we're going to run the script as is, and now lets try to get online... there you go, it doesn't work. This is the line we need to have to allow normal network communication: iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT This means we want to match packets based on their state, and the particular states we want to match are established and related. Finally, with -j we want to accept these packets. Now, as you can see, can receive responses to our connection requests. Tune in 2 weeks as we continue the iptables tutorial.