Iptables appends rule default after “-A INPUT -j REJECT –reject-with icmp-host-prohibited”

iptables

I use iptables to open port 80 for HTTP on CentOS 6.4
I usually use vim to edit the /etc/sysconfig/iptables
But this time I use /sbin/iptables command.

# /sbin/iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
# service iptables save
# service iptables restart

When I list the rules I can see http like this:

ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh 
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited 
ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:http 

But I can not connect to web server from other machine
I checked the iptables file and I see the content like this:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [88:9264]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

I had to manual put the line:

-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

before

-A INPUT -j REJECT --reject-with icmp-host-prohibited

and then when I restart iptables service. It worked!

So how can append new rules in a right way?
Thanks!

Best Answer

The -A command to iptables simply "appends" a rule. So if you're existing ruleset looks like this:

ACCEPT     tcp  --  anywhere             anywhere            state NEW tcp dpt:ssh 
REJECT     all  --  anywhere             anywhere            reject-with icmp-host-prohibited 

And you run:

# /sbin/iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

Then of course this will end up after the REJECT rule (because you told it to append the rule to the existing rulset). You have a few choices:

  1. You can simply edit /etc/sysconfig/iptables by hand, insert the rules you want, and run service iptables restart.
  2. You can use the lokkit tool to modify the firewall instead. E.g., lokkit -p 80:tcp. This will automatically update /etc/sysconfig/iptables as well as the active firewall.
  3. You can use the -I <num> flag to iptables to insert the rule at the specified position in the list. The --line-numbers flag can be useful for figuring out what <num> should be. You'll need to run service iptables save after making changes this way.

If you really want to be able to do this sort of thing using just append commands, you'll need to perform a little setup first. Create a new chain (called, maybe, allow_services):

iptables -N allow_services

And add a rule to your INPUT chain in the appropriate place that jumps to this new chain:

iptables -I INPUT 5 -j allow_services

And from that point on, you can simply append new services to the allow_services chain:

iptables -A allow_services -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

Assuming that you place your jump rule (the -j option) before the final REJECT this will do what you seem to be asking.