iptables rules

I've searched and searched and pretty much come across these two rule sets that seem to be pretty common for starting out in configuring iptables.

Can someone explain to me the differences between these two rule sets?

Rule set 1:

http://www.linode.com/wiki/index.php/Ne … to#Scripts">http://www.linode.com/wiki/index.php/NetfilterIPTablesMini_Howto#Scripts

1: Chain INPUT (policy ACCEPT)
2: target     prot opt source               destination
3: ACCEPT     all  --  anywhere             anywhere
4: ACCEPT     udp  --  anywhere             anywhere            udp spt:domain dpts:1024:65535
5: ACCEPT     tcp  --  anywhere             anywhere            tcp spts:1024:65535 dpt:ssh state NEW
6: ACCEPT     tcp  --  anywhere             anywhere            tcp spts:1024:65535 dpt:www state NEW
7: ACCEPT     tcp  --  anywhere             anywhere            state RELATED,ESTABLISHED
8: DROP       all  --  anywhere             anywhere
9: 
10: Chain FORWARD (policy ACCEPT)
11: target     prot opt source               destination
12: DROP       all  --  anywhere             anywhere
13: 
14: Chain OUTPUT (policy ACCEPT)
15: target     prot opt source               destination
16: ACCEPT     all  --  anywhere             anywhere
17: ACCEPT     udp  --  anywhere             anywhere            udp spts:1024:65535 dpt:domain
18: ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
19: ACCEPT     tcp  --  anywhere             anywhere            state NEW,RELATED,ESTABLISHED multiport dports www,https multiport sports 1024:65535
20: DROP       all  --  anywhere             anywhere

Rule set 2:

This rule set seems to be either more widely used or one person wrote it and a lot of people copied and talked about it….

http://linode.com/wiki/index.php/Config … ntu_server">http://linode.com/wiki/index.php/ConfiguringIPtablesonubuntuserver

1: Chain INPUT (policy ACCEPT)
2: target     prot opt source               destination
3: ACCEPT     all  --  anywhere             anywhere
4: REJECT     all  --  anywhere             loopback/8          reject-with icmp-port-unreachable
5: ACCEPT     all  --  anywhere             anywhere            state RELATED,ESTABLISHED
6: ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:www
7: ACCEPT     tcp  --  anywhere             anywhere            tcp dpt:https
8: ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:30000
9: ACCEPT     icmp --  anywhere             anywhere            icmp echo-request
10: LOG        all  --  anywhere             anywhere            limit: avg 5/min burst 5 LOG level debug prefix `iptables denied: '
11: 11REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable
12: 
13: Chain FORWARD (policy ACCEPT)
14: target     prot opt source               destination
15: REJECT     all  --  anywhere             anywhere            reject-with icmp-port-unreachable
16: 
17: Chain OUTPUT (policy ACCEPT)
18: target     prot opt source               destination
19: ACCEPT     all  --  anywhere             anywhere

Is there a difference between specifying multiple ports in 1 rule or having each port have it's own rule?

I don't understand the LOG part on line 10 of the 2nd rule set.

I also don't understand why the 1st rule set is specifying source ports. What does that do exactly?

What are you opinions on DROP vs REJECT? Do you REJECT packets and inform the user that the connection was refused or do you just DROP them?

Is there something else I should be looking at?

11 Replies

> Is there a difference between specifying multiple ports in 1 rule or having each port have it's own rule?
Technically no, but I'm not sure there is a way to specify multiple non-sequential ports in one line. It'd be fine if you wanted to say "allow traffic on destination ports 1-1000" (please don't do that), but usually you separate rules when saying allow traffic on port 80, and on port 443, etc.

You can also see the byte/packet counts for each rule.

> I don't understand the LOG part on line 10 of the 2nd rule set.
This simply logs anything that has gotten to that point in your ruleset to syslog. In this case, it logs anything that gets rejected. The limit stuff is there so that a maximum of 5 entries per minute will be logged, this prevents your logs from growing dramatically and slowing your system down.

> I also don't understand why the 1st rule set is specifying source ports. What does that do exactly?
Typically, operating systems make outbound connections on non-privileged ports (port 1024 and higher). This rule enforces that connections to services such as ssh and www come from one of these ports. I don't do this on my iptables, so I'm not 100% sure the reasoning behind blocking requests coming from lower numbered ports. Generally "good" traffic will only come from higher ports, but "bad" traffic will not just come from lower ports.

> What are you opinions on DROP vs REJECT? Do you REJECT packets and inform the user that the connection was refused or do you just DROP them?
Drop makes it look like a server isn't even there. Reject says "yes I'm here, but no you can't come it". I tend to use DROP so that someone doing a port scan of random IPs (say a Linode block) doesn't necessarily know I'm there unless they hit on one of my open ports (not that hard to do).

> Is there something else I should be looking at?
The iptables man page is the best thing.

There is tons of stuff on iptables out there. My personal favorite is rate limiting SSH connections to make brute force attacks more difficult:

http://blog.andrew.net.au/2005/02/16/

http://www.linode.com/forums/viewtopic.php?p=6935#6935

Something I noticed right away…in the second ruleset we have:
> -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT And later:
> -A INPUT -p tcp -m state –state NEW –dport 30000 -j ACCEPT
The oversight here is that after the ESTABLISHED,RELATED rule, the only packets moving forward are NEW and INVALID. For every SSH connection, the ruleset is needlessly checking the state, as it's only going to be NEW or INVALID (and you should have a rule to drop INVALID anyway). The method with which I preamble my iptables ruleset is as follows:

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP

After those two rules every packet will be NEW (for TCP, a SYN). I'm not the biggest fan of rejecting unexpected traffic, either; I know it's The Right Thing to do, but in a DDoS situation you're going to be compounding the problem with the rejection packets.

Another thing that really bothers me is blind rejection of all ICMP packets except for type 8. Particularly for IPv6, ICMP serves a lot of uses that naive administrators overlook by dropping them all.

A good rule of thumb to keep in mind when you're dealing with Netfilter is that your most popular traffic should have a decision made on it as soon as possible, to decrease overhead. Another important means of decreasing overhead is doing as few compares as possible before a decision is made. Your most popular traffic is almost always RELATED,ESTABLISHED and that should be the first rule in the table. In these rulesets, the loopback rules are first…which means that for every active connection, you're doing a compare against loopback for every packet, which is a waste of overhead.

The first ruleset doesn't fare much better there, as ESTABLISHED,RELATED is pushed 5 rules down.

Another problem I noticed with both rulesets it that each author adds a rule to the end of INPUT and OUTPUT, without even addressing the chain's policy itself. Every chain has a default policy which, when packets run off the end, gets used (including a friendly counter on the top). For example, to set default DROP on everything:

-P INPUT DROP
-P OUTPUT DROP
-P FORWARD DROP

…yet, these authors add a pointless rule to do the same thing.

I don't like either ruleset (because each strikes me as written by someone not very conscious of Netfilter's workings), and my advice to you would be to play with the rulesets themselves on a non-production box. Verbosely log your traffic at various spots in the chains and see what does what. That's how I taught myself iptables (I didn't adopt Linux early enough to get into ipchains, its predecessor), and once it clicks, it's not that bad.

Edit: Oh, forgot to add – you can look at something like Shorewall, and see how it writes rules.

To help you a bit more, if I were to write a ruleset from scratch (in my head), here's what I'd use. It's far from complete. I prefer scripting iptables instead of using iptables-restore, so this looks different:

# flush all chains and zero the counters
iptables -F INPUT
iptables -F FORWARD
iptables -F OUTPUT
iptables -Z

# easy log/drop chain (so you don't pollute your real chains)
iptables -N KILL
iptables -A KILL -m limit --limit 6/min -j LOG --log-prefix "Drop: "
iptables -A KILL -j DROP

# create privileged chain: stuff in this chain only I should have access to
iptables -N ME
iptables -A ME -s home.workstation.org/32 -j ACCEPT
iptables -A ME -s office.outgoing/32 -j ACCEPT
iptables -A ME -j KILL

# create a BAD chain for hosts that are abusing you
# (let packets run off this one)
iptables -N BAD
iptables -A BAD -s bad.boy/24 -j KILL

# create side chains for new connections
iptables -N ICMP
iptables -N TCP
iptables -N UDP

# now let's actually create rules
# preamble (take care of everything but state NEW)
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state INVALID -j DROP

# take care of localhost
iptables -A INPUT -i lo -s 127.0.0.1/8 -d 127.0.0.1/8 j ACCEPT

# take care of everything else
# note I use eth0 for sanity, feel free to adjust at will or drop the -i rule
# not to us? kill it
iptables -A INPUT -i eth0 ! -d this.server/32 -j KILL

# check for a bad host (drop in that chain, if it runs off it returns here)
iptables -A INPUT -i eth0 -j BAD

# go to our separate chains
iptables -A INPUT -i eth0 -p udp -j UDP
iptables -A INPUT -i eth0 -p icmp -j ICMP

# since all packets at this point TCP and state NEW, the packet should be SYN
iptables -A INPUT -i eth0 -p tcp ! --syn -j KILL
iptables -A INPUT -i eth0 -p tcp -j TCP

# odd, shouldn't get here, log it
# (some still do, it's usually proto 41 stuff or some other Martian packets)
iptables -A INPUT -j LOG --log-prefix "Wut?: "

# (don't forget, run off INPUT chain = DROP)

# TCP chain -- I sort by port number because I'm anal
iptables -A TCP -p tcp --dport 22 -j ME
iptables -A TCP -p tcp --dport 25 -j ACCEPT
iptables -A TCP -p tcp --dport 80 -j ACCEPT
iptables -A TCP -p tcp --dport 587 -j ME
# log failed TCP connections instead of returning to main chain
iptables -A TCP -j KILL
# ...etc

# UDP chain
iptables -A UDP -p udp --dport 53 -j ACCEPT
# silently drop UDP we don't care about (you may wish to log)
iptables -A UDP -j DROP

# ICMP chain
# filter out specific stuff you don't want, and I prefer to allow the rest
# the chain is there for you to customize either way
iptables -A ICMP -j ACCEPT

Don't forget ip6tables, too, if you're IPv6-enabled.

Thanks Jed. That was my main reason for asking when I see 15 different sources seeming blindly spouting off the exact same info (the 2nd ruleset is all over the internet) I really start to question it. People trying to look smart who really don't have a frickin' clue.

The 1st ruleset seems to be someone just blindly copying info from the source:

http://www.netfilter.org/documentation/

I don't know iptables (yet) so I was looking for a "standard" ruleset that's good to use. Since I'm really only using my Linode for web sites, port 80, 443 and 22 are really all I care about. So I just want (I think) to allow any outgoing traffic and for inbound only allow 80, 443 and 22, block/drop all other traffic. Well I do want to allow ICMP. I've never understood why "administrators" block ICMP traffic.

If you are using Ubuntu and your needs are, well, uncomplicated you can try ufw.

> After those two rules every packet will be NEW (for TCP, a SYN). I'm not the biggest fan of rejecting unexpected traffic, either; I know it's The Right Thing to do, but in a DDoS situation you're going to be compounding the problem with the rejection packets.

I prefer to reject packets over dropping. There are two reasons. One is security through obscurity. I use "REJECT –reject-with icmp-host-unreachable" at the end of the INPUT and FORWARD chains. When somebody tries to connect on a port that isn't listening (or ping) they receive:

C:\Users\Me>ping 192.168.1.1

Pinging 192.168.1.1 with 32 bytes of data:
Reply from 192.168.1.1: Destination host unreachable.
Reply from 192.168.1.1: Destination host unreachable.
Reply from 192.168.1.1: Destination host unreachable.

Most tools simply look to see if they receive a destination host unreachable, but if they look closely the system they are attempting to connect to is the one saying the host is unreachable. This will stop most hacking tools

The other reason is that you aren't really compounding the problem by telling the remote system that you aren't unreachable. Yes, you are sending even more traffic, but if you don't send a response then they are holding memory open waiting for your response. If you do send a response then they will process it and release that memory.

Hi,

Thought I'd post something I found on the internet helping to stop ssh brute force attacks. You can set your ssh rule as:

iptables -A INPUT -p tcp –dport ssh -m state --state NEW -m recent --set -j ACCEPT

iptables -I INPUT -p tcp --dport ssh -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Then if someone attempts to log in with an invalid username/password more than 3 times in a minute it will drop them. Lol, I just realized this has been posted here before quite recently.

@davidwelch:

Hi,

Thought I'd post something I found on the internet helping to stop ssh brute force attacks. You can set your ssh rule as:

iptables -A INPUT -p tcp –dport ssh -m state --state NEW -m recent --set -j ACCEPT

iptables -I INPUT -p tcp --dport ssh -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Then if someone attempts to log in with an invalid username/password more than 3 times in a minute it will drop them. Lol, I just realized this has been posted here before quite recently.

Actually, I don't think those rules will work unless you reverse their order.

@davidwelch:

Then if someone attempts to log in with an invalid username/password more than 3 times in a minute it will drop them.

If someone even connects 3 times in a minute, it will drop them, even if they successfully logged in.

Yes, I bang this drum quite hard.

Just to chime in here, as jed is correct in terms of iptables.

For the most part, scanners are typically looking for active service ports. This generally includes stuff you're already going to be listening on for services.

What's the point of an iptables rule to DROP packets to ports 54-79 when port 80 is listening for web traffic?

Any decent web scanner is only going to look for known services ports (this includes applications you're running and scanning for trojan service ports).

That said, a good iptables ruleset is possibly a good idea if you want that much control over your system. Logging potentially damaging traffic is a great idea in a lot of cases, if you're seeing problems. And if you're seeing problems from certain hosts, having a rule to block them isn't a bad idea either.

That said, iptables isn't as important for security as other technologies you can implement.

If you want to block service scanners, a good idea is to run the utility portsentry (and of course iptables) on common service ports below your "protected" ports.

So for sequential port scans of 1-79, you can have portsentry add a drop rule to that host in iptables, so when they get to 80–they don't see that you're running a webserver.

It's an interesting concept, and I've used it in practice, but in the larger scheme of things there are much more security issues to worry about and guard against.

What good is a solid iptables ruleset if your apache is letting every web user write to /etc? (Exaggerated example, but you get the point)

@zibeli:

@davidwelch:

Hi,

Thought I'd post something I found on the internet helping to stop ssh brute force attacks. You can set your ssh rule as:

iptables -A INPUT -p tcp –dport ssh -m state --state NEW -m recent --set -j ACCEPT

iptables -I INPUT -p tcp --dport ssh -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Then if someone attempts to log in with an invalid username/password more than 3 times in a minute it will drop them. Lol, I just realized this has been posted here before quite recently.

Actually, I don't think those rules will work unless you reverse their order.

Nevermind, I just noticed that you're inserting rather than appending the 2nd rule above (-I instead of -A), so since the default insert position is at the start of the chain the second (above) rule will be first in the chain. Sorry for the noise. ;-)

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct