# Please help an iptables n00b!

## stdPikachu

I've been using Linux for some years now, but iptables was never something I've ever really gotten my head around, so I finally decided to bite the bullet and give it a whirl. I've tried using things like fwbuilder to create myself some nice iptables scripts, but have never managed to get any of those to work either, and to be honest I'd rather do this stuff by hand as I'm likely to learn more. Security hasn't been a huge concern since all of this stuff is on a LAN and only SSH is net-facing.

So without further ado, here's the script I've mangled together so far:

```
#!/bin/sh

# firewall script for snafu.local computers

iptables="/sbin/iptables"

trusted_hosts="prospero banquo tybalt tamora"

snafu_network="192.168.1.0/24"

vlan_network="192.168.2.0/24"

# Securify /proc

if [ -e /proc/sys/net/ipv4/tcp_syncookies ]; then echo 1 > /proc/sys/net/ipv4/tcp_syncookies; fi

if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]; then echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter; fi

# flush existing chains etc, drop all incoming, enable outgoing by default (dangerous?)

echo "Flushing current rules..."

$iptables -F INPUT

$iptables -F OUTPUT

$iptables -P INPUT DROP

$iptables -P OUTPUT ACCEPT

echo " done!"

# allow loopback interface

echo "Enabling loopback..."

$iptables -A INPUT -i lo -j ACCEPT

$iptables -A OUTPUT -o lo -j ACCEPT

echo " done!"

# allow established/related connections back in

echo "Enabling state policy..."

$iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

echo " done!"

# ICMP

#$iptables -A OUTPUT -p icmp -m state --state NEW -j ACCEPT

# Accept all previously established connections

#$iptables -A INPUT -p icmp -m state --state ESTABLISHED,RELATED -j ACCEPT

#$iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -i eth0 -j ACCEPT

# drop all usually useless ICMP requests (except for trusted hosts?)

#$iptables -I INPUT -p icmp --icmp-type redirect -j DROP

#$iptables -I INPUT -p icmp --icmp-type router-advertisement -j DROP

#$iptables -I INPUT -p icmp --icmp-type router-solicitation -j DROP

#$iptables -I INPUT -p icmp --icmp-type address-mask-request -j DROP

#$iptables -I INPUT -p icmp --icmp-type address-mask-reply -j DROP

# Begin opening TCP/UDP ports

########################

# Rules for everything #

########################

# Allow SSH from everything

#$iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# better version to stop brute forces

iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m sshbrute --set

iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m sshbrute --update --seconds 60 --hitcount 3 -j DROP

# Up to 5 BitTorrent ports

$iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 6881:6886 -j ACCEPT

#######################

# Rules for local LAN #

#######################

# Allow http/https from local network

$iptables -A INPUT -s $snafu_network -p tcp --dport 80 -j ACCEPT

$iptables -A INPUT -s $snafu_network -p tcp --dport 443 -j ACCEPT

# Allow DNS (TCP + UDP) from local network

$iptables -A INPUT -s $snafu_network -p tcp --dport 53 -j ACCEPT

$iptables -A INPUT -s $snafu_network -p udp --dport 53 -j ACCEPT

# Allow NTPD from local network

$iptables -A INPUT -s $snafu_network -p udp --dport 123 -j ACCEPT

# Allow Samba/NetBIOS

$iptables -A INPUT -s $snafu_network -p udp --dport 137 -j ACCEPT

$iptables -A INPUT -s $snafu_network -p udp --dport 138 -j ACCEPT

$iptables -A INPUT -s $snafu_network -p tcp --dport 139 -j ACCEPT

$iptables -A INPUT -s $snafu_network -p tcp --dport 445 -j ACCEPT

################################

# Rules for trusted hosts only #

################################

for host in $trusted_hosts; do

        echo "Applying firewall rules for $host..."

        # Allow MySQL

        $iptables -A INPUT -s $host -p tcp --dport 3306 -j ACCEPT

        # Allow SMTP

        $iptables -A INPUT -s $host -p tcp --dport 25 -j ACCEPT

        # Allow RPC

        $iptables -A INPUT -s $host -p tcp --dport 111 -j ACCEPT

        $iptables -A INPUT -s $host -p udp --dport 111 -j ACCEPT

        # Allow NFS

        $iptables -A INPUT -s $host -p tcp --dport 2049 -j ACCEPT

        $iptables -A INPUT -s $host -p udp --dport 2049 -j ACCEPT

        # Allow MythTV

        $iptables -A INPUT -s $host -p tcp --dport 6543:6544 -j ACCEPT

        # Allow rsyncd

        $iptables -A INPUT -s $host -p tcp --dport 873 -j ACCEPT

        # Allow Kerberos

        $iptables -A INPUT -s $host -p tcp --dport 88 -j ACCEPT

        $iptables -A INPUT -s $host -p udp --dport 88 -j ACCEPT

        $iptables -A INPUT -s $host -p tcp --dport 749 -j ACCEPT

        # Allow LDAP

        $iptables -A INPUT -s $host -p tcp --dport 389 -j ACCEPT # LDAP

        $iptables -A INPUT -s $host -p tcp --dport 636 -j ACCEPT # LDAPS

done

# Drop all other packets

$iptables -A INPUT -i eth0 -p tcp --dport 0:65535 -j DROP

$iptables -A INPUT -i eth0 -p udp --dport 0:65535 -j DROP

echo "Firewall rules loaded"
```

Every time I run this script, and a few variation thereof (including with the "$iptables -A INPUT -i eth0 -p tcp --dport 0:65535 -j DROP" lines commented out), all network connectivity ceases and I have to restart the machine (damned headless boxes!). I'm guessing that this points at some deeper malady with my systems, but I find it odd that it occurs on all of my machines as opposed to just one so I figure I'm doing something stupid here. Perhaps something to do with the distinction between -A and -I, somethng I'm still unsure of?

Don't concern yourselves if I've got the ports/protocols for some of these things wrong (especially SMB, I can't find anyone who agrees on which ports/protocols different versions need) as I'm sure I'll find that out with trial and error  :Very Happy: 

Can anyone give me any pointers as to where I'm going so badly wrong? Any advice/constructive cries of "You're an idiot! Here's why;" greatly appreciated  :Very Happy: 

----------

## stdPikachu

OK, after much trialling and erroring I have figured out what part of the problem is; those damned policy settings. It seems that as soon as I set a default DENY policy, everything stops working, but I can bring the network back to life by specifying a new ACCEPT all policy.

However almost every exmaple I've seen doesn't need to do this, such as this page here. What's the deal with policies? Are they not overridden by subsequent rules? As far as I can work out the following rules should poke the right pinholes...

Am also finding it tricky to figure out how to output this damned stuff into a log...

----------

## /carlito

Have you tried using firestarter to configure your firewall rules? I also had a lot of troubles configuring my iptables configuration until i decided to emerge firestarter, configured myself a nice config, and fired this config up through my wireless script.

Now i can always modify my rules by hand by editing /etc/iptables.bak

----------

## stdPikachu

Not tried firestarter, no - primarily because it wants to install half of Gnome and there don't seem to be any more DE-agnostic apps that do a similar thing. Besides, I'd like to do the rules from scratch so I can find out exactly what's going on... Most of these boxes are headless too, so using a GUI to do it seems a little silly.

My main problem is that almost all of the iptables tutorials assume that you're setting up a NAT router plus already have a fairly good idea of how iptables works, much more reading beckons evidently...

----------

## Moji

It is hard to read someone else's code so I might be wrong but I don't see you allowing outgoing state/related packages, your line appears commented out.

$iptables -A OUTPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

You could get around it if you had both the very last output rule commented out and the default policy set to accept but if you had the last output rule in or default policy as drop then it would fail to let any other outgoing traffic past.

If you have a logger running then you should add in several logging lines as you work out the script. If you have one before each drop rule then it can help you troubleshoot where you're losing packages.

```
/sbin/iptables -A INPUT -j LOG --log-prefix "Dropped input"
```

or

```
/sbin/iptables -A OUTPUT -j LOG --log-prefix "Dropped output"
```

The basic iptable that I always post for everyone is

```
/sbin/iptables -v --flush

/sbin/iptables -v --delete-chain

/sbin/iptables -v -P INPUT DROP

/sbin/iptables -v -P OUTPUT DROP

/sbin/iptables -v -P FORWARD DROP

/sbin/iptables -v -A OUTPUT -o lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

/sbin/iptables -v -A INPUT -i lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

/sbin/iptables -v -A OUTPUT -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

/sbin/iptables -v -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 1024:65535 --dport 80 -j ACCEPT #HTTP

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 1024:65535 --dport 443 -j ACCEPT #HTTPS

/sbin/iptables -v -A OUTPUT -o eth0 -p udp --sport 1024:65535 --dport 53 -j ACCEPT #DNS

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 68 --dport 67 -j ACCEPT #DHCP
```

I'm not sure how much you know about iptables so excuse me if I go over things you already know, but if you already have a connection then the INPUT RELATED,ESTABLISHED rule will let incoming traffic to the computer with that connection. That means you really only need to add  additional input rules if you have a service that is running on your computer that is waiting for someone else to connect to. Such as ssh.

If your computers fail under even simple iptables then make sure that you have Kernel Support

I hope that helps some.

-MJ

----------

## Moji

I did not even think of this at first but you can also just do a list of your iptables and you can see which rule is dropping your packages.

```
/sbin/iptables -L -vn | less
```

It should output a list of all the rules that are in your iptables. Just look for where your packages are getting held up.

 *Quote:*   

> Chain AcceptOut (14 references)
> 
>  pkts bytes target     prot opt in     out     source               destination         
> 
>    69  4160 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0

 

-MJLast edited by Moji on Wed Apr 18, 2007 3:51 pm; edited 1 time in total

----------

## stdPikachu

Moji, thanks for that! Highly appreciated as I can pick at your rules one by one instead of being overwhelmed by a huge bash script involving eight zillion loops for NATting 700 subnets  :Very Happy: 

I'm at work at the moment and not risking any changes to the firewalling code whilst working on it through SSH but will give it a whirl when I get back. Since it's just a "personal" firewall for a couple of home machines I'm not too concerned with egress filtering yet, but no doubt it'll creep it's way in as soon as I've found out how the rest of it works  :Very Happy: 

Correct me if I'm wrong, but doesn't the output line need to be NEW,ESTABLISHED,RELATED in order to allow all new outgoing connections as well as established ones?

----------

## Moji

If that was the only rule then yes. But what is happening with the firewall above is that the "NEW" state packet gets out through the port rules, then once its out (and the connection moves ports) its considered "ESTABLISHED" so it gets out through the ESTABLISHED rule.

Thats also why you don't need to make input rules other than the "ESTABLISHED,RELATED" because for most people (not you since you at least are using ssh, port 22) they should only receive information that is incoming as a result of a outgoing request.

Until a packet is dropped it goes through the ipchain and only has to be accepted once for it to enter into the system.

-MJ

----------

## Moji

I am sorry but I left out some important ports, a friend was putting up a fileserver/media center and asked me to write a firewall for it. While I was writing his firewall I realized that I had forgot to put in ftp and RSYNC! in the posting I made earlier. So sorry if I caused any frustration when you were trying to sync.

```
/sbin/iptables -v --flush

/sbin/iptables -v --delete-chain

/sbin/iptables -v -P INPUT DROP

/sbin/iptables -v -P OUTPUT DROP

/sbin/iptables -v -P FORWARD DROP

/sbin/iptables -v -A OUTPUT -o lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

/sbin/iptables -v -A INPUT -i lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

/sbin/iptables -v -A OUTPUT -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

/sbin/iptables -v -A INPUT -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 1024:65535 --dport 80 -j ACCEPT #HTTP

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 1024:65535 --dport 443 -j ACCEPT #HTTPS

/sbin/iptables -v -A OUTPUT -o eth0 -p udp --sport 1024:65535 --dport 53 -j ACCEPT #DNS

/sbin/iptables -v -A OUTPUT -o eth0 -p udp --sport 1024:65535 --dport 873 -j ACCEPT #RSYNC

/sbin/iptables -v -A OUTPUT -o eth0 -p udp --sport 1024:65535 --dport 21 -j ACCEPT #FTP

/sbin/iptables -v -A OUTPUT -o eth0 -p tcp --sport 68 --dport 67 -j ACCEPT #DHCP
```

-MJ

----------

## stdPikachu

Thanks again for the info!

The main box I'm securing does have quite a few services running on it (LDAP, Kerberos, NFS, blah blah blah...) but I might consider writing a ruleset that allows anything from a list of trusted hosts (defined by IP and MAC address) rather than poking holes, which I'll only need to do for "global" daemons like bind which need to be made available to the whole subnet.

Last night was spent fighting with OpenSSL, so haven't had the chance to tinker with it too much yet...! More as it comes...

----------

## Moji

In the ruleset that I wrote for this fileserver I split the packet stream into four chains, LAN packets incoming, LAN packets outgoing, Outside LAN incoming, Outside LAN outgoing.

Then I check each element of a packet one at a time in subchains. I did this for him because it will be easy for him to going in and add ports by just finding the port subchain for either LAN/External and then just copying and pasting the rule, only changing the port or ip as he needed. 

```
PACKET

|

|--LAN

|  |--INCOMING->device->ip->port->Accept

|  |--OUTGOING->device->ip->port->Accept

|--OTHER

   |--INCOMING->device->ip->port->Accept

   |--OUTGOING->device->ip->port->Accept
```

It is always easier for me if I make rules that check only one element at a time so that it is easy to trace problems as I create a ruleset.

The output of listing your iptables is most helpful as you can just look at the left column and find exactly where packets are sticking. Best of luck.

```
/sbin/iptables -L -vn | less
```

-MJ

----------

