August 26, 2009

Configuring Egress (Outbound) Rules with iptables (ubuntu style)

There is a lot of information on iptables (the Linux firewall) out there, but most of them focus on ingress rules.

Unfortunately, in many cases, simply creating ingress rules are insufficient. On systems you really want to secure, you should also set up egress (outbound) rules to restrict outbound traffic.

NOTE: The commands in this post assume a Debian-based distribution (e.g., Ubuntu server). The iptables commands should be the same across distributions, but check your own distro’s reference guide for how to save and load iptables as those steps vary.

ALSO NOTE: Because of the column width in this blog, some of the rules wrap to a second
line. Keep in mind that all the lines start with “sudo iptables”.

In the below example, we’ll set up fairly common rules for a server that only really
needs to get package updates. Remember that these are case sensitive commands, and
also that the order you type them is the order that they are evaluated (i.e., if you
are connecting over SSH, don’t do the -A OUTPUT -j REJECTfirst).

sudo iptables -A OUTPUT -o lo -p all -j ACCEPT

sudo iptables -A OUTPUT -m state –state RELATED, ESTABLISHED

sudo iptables -A OUTPUT -p tcp –dport 80 -d

sudo iptables -A OUTPUT -p tcp –dport 80 -d

sudo iptables -A OUTPUT -j REJECT

IMPORTANT: Do not add the security.ubuntu.comor us.archive.ubuntu.comrules
unless you make a /etc/hostsentry for those…otherwise
you will also need to let DNS out and it will be SLOW.

Let’s take a look at each of these rules:


sudo iptables -A OUTPUT -o lo -p all -j ACCEPT

This is adding an entry saying that we should accept any traffic that wants to go
outbound on the local ( interface. Some applications use this interface
to exchange information, and we don’t want to break those.


sudo iptables -A OUTPUT -m state –state RELATED,

This is the “secret sauce” rule, and one that is often forgotten, leading to disconnected
sessions and confusion. What this says is allow outbound traffic that associated with
a session that is already established or related to an established session. For example,
if you have SSH on your server, you can open up port 22 inbound, but how will the
server send data back to clients (that may even suggest an alternate higher port for
subsequent communications)? That’s what this rule allows.


sudo iptables -A OUTPUT -p tcp –dport 80 -d -j ACCEPT

sudo iptables -A OUTPUT -p tcp –dport 80 -d


These rules simply tell iptables to allow traffic going to port 80 for ubuntu’s update
servers. These may be different depending on your region, and there may be more, so
you will have to do an apt-get update after you do this to make sure that it works
for you. IMPORTANT: As I mentioned before, DO NOT enable these rules without first
putting an entry mapping the appropriate IP’s in /etc/hosts.
Also if Ubuntu changes these IP’s, you will need to update your hosts entry. Otherwise
you would have to enable DNS to resolve those names and there could potentially be
an external lookup for every outbound packet (ouch!).


sudo iptables -A OUTPUT -j REJECT

This is the rule that kills all the other traffic. This should definitely be the last
rule in your chain, or the other rules won’t work.

That’s it!

Don’t forget to do:

sudo sh -c “iptables-save gt; /etc/iptables.rules”

if you want to keep the rules, and then add:

pre-up iptables-restore lt; /etc/iptables.rules

under the interface (eth0 or whatever) in /etc/network/interfaces.

Here are some other egress rules you may be interested in:

To allow “ping” to work (from the server):

sudo iptables -A OUTPUT -p icmp –icmp echo-request

sudo iptables -A OUTPUT -p icmp –icmp echo-reply -j ACCEPT

To allow DNS to work (from the server):

sudo iptables -A OUTPUT -p tcp –dport 53 -j

sudo iptables -A OUTPUT -p udp –dport 53 -j ACCEPT

So now you have no excuse to leave your outbound traffic unguarded…get to it!