A firewall is a machine that sits between a network and the rest of the Internet, attempting to ensure that nothing "bad" from the Internet harms the network. You can also set up firewall features for each machine, where the machine screens all of its incoming and outgoing data at the packet level (as opposed to the application layer, where server programs usually try to perform some access control of their own). Firewalling on individual machines is sometimes called IP filtering.
To understand how firewalls work, consider that there are three times when a system can filter packets:
When the system receives a packet
When the system sends a packet
When the system forwards (routes) a packet to another host or gateway
With no firewalling in place, a system just processes packets and sends them on their way.
Firewalls put checkpoints for packets at the points of data transfer identified above. The checkpoint drops, rejects, or accepts packets, usually based on some of these criteria:
The source or destination IP address or subnet
The source or destination port (in the transport layer information)
The firewall's network interface
In Linux, you create firewall rules in a series known as a chain that is part of a networking table (for the most part, you will only work with one table named filter that controls basic packet flow). The iptables command, available since kernel version 2.4.0, manipulates these rules and chains. To use iptables, your kernel configuration must have packet filtering (in the networking options) and IP tables support (in the netfilter configuration submenu). You will learn more about kernel configuration in Chapter 10.
There are three basic chains: INPUT for incoming packets, OUTPUT for outgoing packets, and FORWARD for routed packets. To view the current configuration, run this command:
iptables -L
The iptables command should list an empty set of chains, as follows:
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
Each chain has a default policy that specifies what to do with a packet if no rule matches the packet. The policy for all three chains in this example is ACCEPT, meaning that the kernel allows the packet to successfully pass through the packet-filtering system. For the purposes of this book, the only other value that makes any sense is DROP, which means that the kernel will discard the packet. To set the policy on a chain, use iptables -P as in this example:
iptables -P FORWARD DROP
Warning? |
Don't do anything rash with the policies on your machine until you've read through the rest of this section. |
Let's say that someone at 192.168.34.63 is annoying you, so you'd like to prevent them from talking to your machine. Run this command:
iptables -A INPUT -s 192.168.34.63 -j DROP
The -A INPUT parameter appends a rule to the INPUT chain. The -s 192.168.34.63 part specifies the source IP address in the rule, and -j DROP tells the kernel to discard any packet matching the rule. Therefore, your machine will throw out any packet coming from 192.168.34.63.
To see the rule in place, run iptables -L:
Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 192.168.34.63 anywhere
As luck would have it, though, your good buddy at 192.168.34.63 has told everyone on his subnet to open connections to your SMTP port (TCP port 25), so now you want to get rid of that traffic as well:
iptables -A INPUT -s 192.168.34.0/24 -p tcp --destination-port 25 -j DROP
This example adds a netmask qualifier to the source address, as well as -p tcp to specify TCP packets only. A further restriction, --destination-port 25 says that the rule should only apply to traffic to port 25. The IP table list for INPUT now looks like this:
Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 192.168.34.63 anywhere DROP tcp -- 192.168.34.0/24 anywhere tcp dpt:smtp
All is well until you hear from someone you know at 192.168.34.37, saying that they can't send you email because you blocked their machine. Thinking that this is a quick fix, you run this command:
iptables -A INPUT -s 192.168.34.37 -j ACCEPT
However, it doesn't work. For the reason, look at the new chain:
Chain INPUT (policy ACCEPT) target prot opt source destination DROP all -- 192.168.34.63 anywhere DROP tcp -- 192.168.34.0/24 anywhere tcp dpt:smtp ACCEPT all -- 192.168.34.37 anywhere
The kernel reads the chain from top to bottom, using the first rule that matches. The first rule does not match 192.168.34.37, but the second does, because it applies to all hosts from 192.168.34.1 to 192.168.34.254, and this second rule says to drop packets. Once a rule matches, the kernel carries out the action and does not look further down in the chain. (You might remark that 192.168.34.37 can send packets to any port on your machine except port 25, because the second rule only applies for port 25.)
Therefore, you have to move the third rule to the top. The easiest way to do this is to first delete the third rule with this command:
iptables -D INPUT 3
Then, insert that rule at the top of the chain with iptables -I:
iptables -I INPUT -s 192.168.34.37 -j ACCEPT
If you want to insert a rule at some other place than the top of a chain, put the rule number after the chain name (for example, iptables -I INPUT 4 ...).
Although this little tutorial may show you how to insert rules and how the kernel processes IP chains, it doesn't even come close to illustrating firewall strategies that actually work. Let's talk about that now.
There are two basic kinds of firewall scenarios: one for protecting individual machines (where you set rules in each machine's INPUT chain), and one for protecting a network of machines (where you set rules in the router's FORWARD chain). In both cases, you cannot expect to have serious security by using a default policy of ACCEPT, continuously inserting rules to drop packets from sources that start to send bad stuff to you. Instead, you must adopt the strategy of allowing only the packets that you trust and denying everything else.
For example, let's say that your machine has an email server on TCP port 25 and an SSH server on TCP port 22. There is no reason for any random host to talk to any other port on your machine, and you shouldn't give any such host a chance. Here's how to set it up.
First, set the INPUT chain policy to DROP:
iptables -P INPUT DROP
If you want to enable ICMP traffic (for ping and other utilities), use this line:
iptables -A INPUT -p icmp -j ACCEPT
Let's say that your host's IP address is my_addr. Make sure that you can receive packets sent from yourself to both your own network IP address and 127.0.0.1 (localhost):
iptables -A INPUT -s 127.0.0.1 -j ACCEPT iptables -A INPUT -s my_addr -j ACCEPT
If you have control of your entire subnet (and trust everything on that subnet), you can replace my_addr with your subnet address and subnet mask; for example, 10.43.201.0/24.
Now, although you need to make sure that your host can make TCP connections to the outside world, you still want to deny all incoming TCP connections. Because all TCP connections start with a SYN (connection request) packet, if you let all TCP packets through that aren't SYN packets, you are still okay:
iptables -A INPUT -p tcp '!' --syn -j ACCEPT
Next, you must accept traffic from your nameserver so that your machine can look up names with DNS. Do this for all DNS servers in /etc/resolv.conf. Assuming that the nameserver's address is ns_addr, you can do this with this command:
iptables -A INPUT -p udp --source-port 53 -s ns_addr -j ACCEPT
As mentioned before, you want to allow SSH and SMTP connections from anywhere:
iptables -A INPUT -p tcp --destination-port 22 -j ACCEPT # ssh iptables -A INPUT -p tcp --destination-port 25 -j ACCEPT # smtp
Finally, you need the following command to enable outgoing passive FTP connections, though it's not terribly critical:
iptables -A INPUT -p tcp --source-port 20 --destination-port 1024: -j ACCEPT
The preceding IP table settings work for many situations. For example, they work for any direct connection, especially broadband, where an intruder is much more likely to port-scan your machine. They work for university environments, which are very similar to regular broadband connections. And you could also adapt these settings for a firewalling router, using the FORWARD chain instead of INPUT, and using source and destination subnets where appropriate. However, if you are using a firewalling router, you might find the discussion of NAT in Section 5.14 more applicable to your situation.
Remember that the key idea is permitting only the things that you find acceptable, not trying to find stuff that is unacceptable. Furthermore, IP firewalling is only one piece of the security picture. See Section 6.7 for more information.
This section is a quick reference for the most common iptables options.
All iptables invocations must have a command option, as listed in Table 5-3.
Command Option |
Description |
---|---|
-L chain |
Lists rules (chain is optional). |
-A chain |
Appends a rule to chain. |
-I chain rulenum |
Inserts a rule in chain (rulenum is optional; the default location is the beginning of the chain). |
-D chain rulenum |
Deletes rulenum from chain. You can omit the rule number if you specify a matching parameter (shown in Table 5-4). |
-F chain rulenum |
Deletes all rules in chain, leaving only the policy. |
-P chain newpolicy |
Sets the policy (default rule) of chain to newpolicy. |
Parameter Option |
Meaning |
---|---|
-s addr/mask |
Selects source IP address addr with optional netmask mask (for an entire subnet). |
-d addr/mask |
Selects destination IP address addr with optional netmask mask (for an entire subnet). |
-i interface |
Selects input interface (e.g., eth0, ppp0). |
-o interface |
Selects output interface (e.g., eth0, ppp0). |
-p protocol |
Selects protocol (e.g., tcp, udp, icmp). |
--source-port port |
Selects source port. You may specify a range with port1:port2. This works in conjunction with -p tcp or -p udp. |
--destination-port port |
Selects destination port. You may specify a range with port1:port2. This works in conjunction with -p tcp or -p udp. |
--syn |
When using -p tcp, selects SYN (connection request) packets. |
When using -A and -I (and -D without a rule number), you must specify the rule to add or delete as a combination of the packet specification options in Table 5-4. In addition, you can insert a literal ! after the option flag to negate its meaning.
To finish off your rule, use -j target to decide what to do if a packet matches the rule (the most common types of target are ACCEPT and DROP).
This section has only described the basics of iptables. There are many advanced features, such as the ability to send a packet to an entirely different destination, to intercept packets at different parts of the routing process, and to create your own subchains. You can read about them in the iptables(8) manual page.