I need to configure my machine as to allow HTTP traffic to/from serverfault.com only. All other websites, services ports are not accessible. I came up with these iptables rules:
#drop everything
iptables -P INPUT DROP
iptables -P OUTPUT DROP
#Now, allow connection to website serverfault.com on port 80
iptables -A OUTPUT -p tcp -d serverfault.com --dport 80 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
#allow loopback
iptables -I INPUT 1 -i lo -j ACCEPT
It doesn't work quite well:
After I drop everything, and move on to rule 3:
iptables -A OUTPUT -p tcp -d serverfault.com --dport 80 -j ACCEPT
I get this error:
iptables v1.4.4: host/network `serverfault.com' not found
Try `iptables -h' or 'iptables --help' for more information.
Do you think it is related to DNS? Should I allow it as well? Or should I just put IP addresses in the rules? Do you think what I'm trying to do could be achieved with simpler rules? How?
I would appreciate any help or hints on this. Thanks a lot!
With IPTables rules, order matters. The rules are added, and applied, in order. Moreover, when adding rules manually they get applied immediately. Thus, in your example, any packets going through the INPUT and OUTPUT chains start getting dropped as soon as the default policy is set. This is also, incidentally, why you received the error message you did. What is happening is this:
While the source/destination options will accept hostnames, it is strongly discouraged. To quote the man page,
Slillibri hit the nail on the head which his answer, you missed the DNS ACCEPT rule. In your case it won't matter, but generally I would set the default policy later on the process. The last thing you want is to be working remotely and allow SSH after turning on a default deny.
Also, depending on your distribution, you should be able to save your firewall rules such that they will be automatically applied at start time.
Knowing all that, and rearranging your script, here is what I would recommend.
Add
to allow DNS lookups.
This kind of requirement may be better handled with a web proxy and/or filter. Dansgaurdian can be configured to do this. You will need to use NAT rules to force your traffic through the filter.
Using iptables to filter will allow any sites available from the relevant IP addresses. This is normally a small subset of the entire web.
I'm afraid iptables doesn't work at this level, it only cares about the ip address, not the hostname. If you want to block access to other name virtual hosts on the same ip, you'll need to look at putting in .htaccess files.
You need to configure this at your webserver. iptables is a packet filter. HTTP transactions send the site name (i.e. stackoverflow) as part of the TCP payload (i.e. not as part of the TCP header which is what iptables reads easily).
Given that, and the fact that HTTP transactions are almost certainly going to be spread over multiple packets (i.e. you can't just match a string in the HTTP header), this is much better handled by your webserver configuration or by a proxy in front of it.
It would be useful to know the reasoning behind this, there are a couple of other alternatives: