Simple firewall for Ubuntu using iptables

Linux's built-in firewall iptables is very useful, but pretty hard to configure. I used to use lokkit, but this caused problems when moving between different networks. I was also having problems with the network configuration tools in Ubuntu, which work but aren't automatic enough for me. And I wanted to be able to switch the firewall and the network configuration simultaneously.

In the end, I bit the bullet and worked out how to write a simple iptables script. Here it is:

#!/bin/bash
# flush all chains
iptables -F
# set the default policy for each of the pre-defined chains
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# allow establishment of connections initialised by my outgoing packets
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# drop everything else
iptables -A INPUT -i eth+ -p udp -j DROP
iptables -A INPUT -i eth+ -p tcp -m tcp --syn -j DROP
# accept anything on localhost
iptables -A INPUT -i lo -j ACCEPT

I have network interfaces on eth0 and eth1, so this script has rules which cover both; if your interfaces have different names, you will need to edit the rules to cover that. This drops everything incoming, except for connections which were initially established by my outgoing packets (thanks Luke! - see comments); which means it's no good for servers.

I put this script in /opt/scripts/iptables.script and made it executable. Once you run it, you can find out whether it has worked by displaying your current iptables rules with:

sudo iptables -L -v

I then created a simple init script to start/stop the firewall (in /etc/init.d/firewall):

#!/bin/bash
if [[ $1 == start ]] ; then
  sudo /opt/scripts/iptables.script
else
  sudo iptables -F
fi

Then I symlinked this into my /etc/rc.* directories using the update-rc.d tool, so the firewall starts before the network comes up:

update-rc.d firewall start 20 2 3 4 5 . stop 99 0 1 6 .

I find having this script helps me a lot. I have it integrated with a start/stop script with my network, so I can easily switch network and firewall configuration from the command line.

Comments

Iptables for just browsing

Guys any iptables for ubuntu for just browsing and secures the various states like 1-7 as also stops service requests on established connections. Also do i need to make changes on sysctl for the iptables to work? in case of kernel panic how does this ipables handle it?

Your iptables script

Thanks for your script, very nice. I especially like the part about update-rc.d. Your iptables script and the info on update-rc.d has given me a starting point and inspired me to delve deeper into iptables and start-up procedures in general.

All the best,
James

Hi,I have some problems

Hi,I have some problems about iptables rules under Ubuntu .
Is it necessary to create some script llike before to build the firewall,Will the rules got lost when I restart the server.

I create a simple firewall with the function of NAT,then restart the server.
type commands below in the terminal:
iptables -L -v

But display nothing.
And it seemd that the NAT function and the rules made last time are still available to use.

Hoping for your email.
Thanks.

Is this necessary?

As far as I was aware, the default ubuntu firewall rules block all unsolicited incoming traffic.

What does this do that is not already happening?

Or am I missing something obvious?

That might be the case now

That might be the case now (I notice Fedora now comes with default firewall rules, which I'm pretty sure it never used to). It wasn't the case on Ubuntu a few years ago when I wrote this article, however.

Time passes, things change :)

This worked perfectly for my

This worked perfectly for my needs. Thanks!

For those who want to ACCEPT specific ports for services like HTTPD, be sure to put those rules before the DROP rules. I fiddled with this for an hour before I figured out that the first rule that matches is the one that gets applied.

eg.

  1. Allow specific TCP inputs
    iptables -A INPUT -i eth0 -p tcp -m tcp --dport 22 -j ACCEPT # ssh
    iptables -A INPUT -i eth0 -p tcp -m tcp --dport 80 -j ACCEPT # http

iptables -A INPUT -i eth1 -p tcp --dport 3306 -s 10.176.84.219 -j ACCEPT
iptables -A INPUT -i eth1 -p tcp --dport 3306 -s 10.176.85.10 -j ACCEPT

  1. drop everything else
    iptables -A INPUT -i eth+ -p udp -j DROP
    iptables -A INPUT -i eth+ -p tcp -m tcp --syn -j DROP

My example got formatted

My example got formatted queerly. The 1's are actually script comments. Cheers!

I was once try out the

I was once try out the ubuntu, but end up keep getting error on the eth0, in which I think it is related to the network card that I have. I try your script which I thought it got something to do with my error, but still fail. Would a firewall cause my eth0(network card) to have such error? I've tried changed few cards which is still the same.

Simpler Alternative (?)

For a personal home computer (running no services for the outside world), here is a simpler version :

#!/bin/bash
############################################################
#---- Script to setup a simple firewall using iptables -----
###
# * Blocks all incoming connections, except those opened by
# me, or related to already open connections
# * Blocks all forward requests
# * Allows all outgoing connections
###
############################################################

# Clearing all previous rules
iptables -F
# Setting Default Policies
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
# Allowing already-established and related-incoming connections
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

Ooops! Forgot the LocalHost...

iptables -A INPUT -i lo -j ACCEPT

Thanks. That does look like

Thanks. That does look like an improvement. Like I said in the post, I'm not really an iptables expert!

firewall init.d script

if you change the POLICIES to DROP and run the init.d script with anything other than a "start" argument, you will flush your rules, but since the policy is DROP , you will not be able to access

firewall

Hi,
Great script - I've used it as the starter for my setup.

ShieldsUP notes that your script shows ports 0 and 1 as closed rather than in stealth mode, and also doesn't drop ICMP packets - meaning that if the machines are directly attached to the internet via ppp, or with an ADSL modem with no firewall, then they can be discovered.

Also your script doesn't handle dialup connections.

The following changes mitigates against these:

  1. drop everything else on ppp
    iptables -A INPUT -i ppp+ -p udp -j DROP
    iptables -A INPUT -i ppp+ -p tcp -m tcp --syn -j DROP
    iptables -A INPUT -i ppp+ -p icmp -j DROP
  2. Explcitly deal with port 0
    iptables -A INPUT -j DROP -p tcp --sport 0
    iptables -A INPUT -j DROP -p udp --sport 0
    iptables -A INPUT -j DROP -p tcp --dport 0
    iptables -A INPUT -j DROP -p udp --dport 0
  3. Explcitly deal with port 1
    iptables -A INPUT -j DROP -p tcp --sport 1
    iptables -A INPUT -j DROP -p udp --sport 1
    iptables -A INPUT -j DROP -p tcp --dport 1
    iptables -A INPUT -j DROP -p udp --dport 1

regards

Colin

short and sweet, works as

short and sweet, works as advertised! happy customer here.

Great, glad it was helpful.

Great, glad it was helpful.

iptables

One of the most impressive tools for building iptables firewalls is fwbuilder at www.fwbuilder.org.
This fantastic GUI app writes the iptables for you in a way that is easy to read.

Really good for heavy weight firewalling.

Roy.

Thanks for that, Roy. I've

Thanks for that, Roy. I've used some of the GUIs before, but the simple ones can't cope with the scenario outlined in the article. While fwbuilder probably could, I like the simplicity of my script, and have used it succesfully without touching it for about 3 years. I'm very happy with it.

So simple!

I've fooled with iptables off and on for a few years now. Never quite getting all the pieces right. Thanks for bringing it back down to Earth with a simple as pie approach to setting the rules and integrating with start up. It was good to learn a thing or two about update-rc.d. That was an interesting tool I hadn't seen before.

One note: Add your input accept rules (like port 80 for HTTP BEFORE you drop everything else). Took me a couple minutes to figure that one out, but otherwise, all else was smooth sailing.

--Michael

Thanks Michael. Glad to be

Thanks Michael. Glad to be of service.

Hello, Very useful article

Hello,

Very useful article but one thing is missing, I think. You need rule like this: IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT to allow for instance dns queries.

Regards
Luke

Hello Luke. Thanks for the

Hello Luke. Thanks for the feedback. The rules I've got here are the ones I use every day. I found that providing I had a rule like this:

iptables -A INPUT -p udp -s 0/0 --sport 53 -d 0/0 -j ACCEPT

(which is included in the above script) I had no trouble getting DNS queries to work. Without this, it didn't work correctly. What does your suggested rule do? I'm not familiar with the state settings (like I say, I'm no iptables expert!).

Hello again

Hi,

Rule like IPTABLES -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT accepts connections that were once OK'ed. So with this rule you don't need yours: iptables -A INPUT -p udp -s 0/0 --sport 53 -d 0/0 -j ACCEPT.
And it is more secure since your port 53 UDP is not opened.

Luke

Hello Luke, thanks for

Hello Luke, thanks for clearing that up. I'll give it a go and change this howto once I'm happy I've got it working. Cheers for the tips.

Your welcome :)

cheers

Help with IPtables config

Greetings,

I would spell out everything I'm trying to do with IPtables but, to save time, I'll point you to the thread I started at http://ubuntuforums.org/showthread.php?t=337024

I've written my IPtables rules, saved them to a text file, and I'm now trying to install the rules I've written. I didn't think this portion of the process was going to be more difficult then actually learning IPtables, but go figure.

Anyway, I'm about to tear my hair out and would greatly appreciate your feedback.

Thank you for your time,

Nick

Nick, the above outline is

Nick, the above outline is how I do this myself. A few clarifications:

  • Where you put iptables.script is irrelevant, but you probably just want to have root own it and make it executable just by root.
  • The script flushes any existing firewall setup: that's why you need to run it before the network comes up. Don't worry about iptables-save or any of that stuff. There are probably tools you can use to do this, but I found them overly confusing. Issuing iptables commands directly works and is concise and portable. (I've used the same scripts, stored in my home directory, for a few years, and just symlink them, with update-rc.d if available, when I install a machine. They should work on any Linux distro, without needing you to add any other software, so could technically work on an extremely minimal Linux.)
  • Shorewall, Webmin, Firestarter etc. will do the firewall config. for you. My issue is that I swop network interfaces (wired at work, wireless at home) and I couldn't find a config. tool (at the time) which would enable me to set different firewall settings on different interfaces at the same time as I switched interface. I use a script to do this now, with hard-coded IP addresses, so it's quick.
  • If you want to allow incoming connections, you just need a line to enable access on the appropriate port. For example to allow incoming HTTP in iptables.script:
    iptables -A INPUT -p tcp -s 0/0 --dport 80 -j ACCEPT
    
  • If you run the above script as root (e.g. just do chmod +x /opt/scripts/iptables.script then ./iptables.script), it will set the iptables permissions there and then. You can either do this at boot time from /etc/init.d or manually while the machine is up.
  • The second script in /etc/init.d/firewall calls the /opt/scripts/iptables.script script. I use update-rc.d to symlink /etc/init.d/firewall into the correct rc.d directories. That's all you need to do to "install" the script. Again, chown root.root /etc/init.d/firewall and chmod u+x /etc/init.d/firewall are probably necessary.

Hope this helps.

sudo

I'm new to all this so please bear with me! In your init script you use sudo to run the script, this is obviously necessary, but does that mean you've edited the sudoers file in order to launch that script without a pwassword?

I think (I'm not sure) that

I think (I'm not sure) that the script will run as root when you boot the machine (in all honesty, sudo is a mystery to me). The sudo is just there if you want to run the script as a normal user in the normal course of things. On Ubuntu, you could probably leave this out if you are only going to run the script as root (or during boot).

Easy Firewall Generator

For simple and effective firewall script try using Easy Firewall Generator
http://easyfwgen.morizot.net/gen/
It works as generator for you on end you simply have firewall.sh that you put where you want.
And you can always install it on your web server to have it locally so you can generate firewall.

Boris

Thanks for the reference.

Thanks for the reference. Could be useful for slightly more complex setups, but for my purposes it's over-kill. I like my short simple script which works in my environment.

Thank you!

Thank you for you iptables script. I have used your script every time I format my Linux machines. Its very handy. Its small and simple. I'm using pppoe connection so i have not created any links in initd but i call my firewall in my ppoe connection.

-TusharG

Glad you find it useful.

Glad you find it useful. When I was writing it, it was surprisingly hard to find simple examples, hence my howto.

thanks!

thanks!

You're welcome!

You're welcome!

shit

when i typed /etc/init.d/firewall stop ssh, apache gone away .. :(
why ?

What, the ports became

What, the ports became unavailable? Or the services stopped running? When you stopped the firewall? If you set it up as above, stopping the firewall shouldn't touch other services, and should definitely not block them.

Thx ;)

thanks!though iptables -A INPUT -p tcp -s 0/0 --dport 80 -j ACCEPT is needed!

Only if you're running a web

Only if you're running a web server :)