23

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!

2
  • 2
    Don't forget sstatic.net and others. serverfault.com doesn't entirely come from serverfault.com
    – Zoredache
    Jan 5, 2011 at 2:18
  • Can you run a proxy on another system? This is the best/easiest solution: serverfault.com/questions/215134
    – mattdm
    Jan 5, 2011 at 2:29

5 Answers 5

33

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:

  1. The default DROP policy get applied
  2. IPTables receives a hostname as a destination
  3. IPTables attempts a DNS lookup on 'serverfault.com'
  4. The DNS lookup is blocked by the DROP action

While the source/destination options will accept hostnames, it is strongly discouraged. To quote the man page,

Hostnames will be resolved once only, before the rule is submitted to the kernel. Please note that specifying any name to be resolved with a remote query such as DNS is a really bad idea.

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.

# Allow loopback
iptables -I INPUT 1 -i lo -j ACCEPT

# Allow DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# 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

# Drop everything
iptables -P INPUT DROP
iptables -P OUTPUT DROP
5
  • 3
    Beautiful, well crafted answer. Jan 5, 2011 at 2:51
  • 1
    I appreciate it, though you must also have missed my mistake. Oops.
    – Scott Pack
    Jan 5, 2011 at 3:03
  • 3
    Actually, you can put your iptables -P statements anywhere in your script, since chain policies are only applied when packets "fall off" the end of a chain. I usually put the policy statements (typically DROP policies) at the top of my iptables scripts. Jan 5, 2011 at 5:57
  • 1
    @Steven: You're absolutely right. The OP appears to be typing them in interactively. Let's pretend you are connected to your host over SSH and your first rule is for the policy DROP. Your SSH connection will be dropped before you can type in any more rules. This is the same timing issue, if a different manifestation, than she ran into.
    – Scott Pack
    Jan 5, 2011 at 12:39
  • Thanks. Was trying this. But didn't work without adding sudo iptables -I OUTPUT 1 -o lo -j ACCEPT. Shouldn't that be added ? Jun 11, 2016 at 10:47
7

Add

iptables -A OUPUT -p udp --dport 53 -j ACCEPT

to allow DNS lookups.

0
5

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.

1
  • 1
    Totally agree with this. iptables is probably the wrong tool to use here, as it doesn't deal particularly well with DNS names. A web proxy with appropriate filter settings is a much better fit. Jan 5, 2011 at 6:06
2

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.

3
  • The thing is, when I try rule 3 without "dropping everything" it works fine with iptables!
    – Zenet
    Jan 4, 2011 at 20:33
  • 2
    hmm, I misread the question. Right, what's happening in the background is that iptables will resolve serverfault.com to 64.34.119.12 (see answer from slillibri to understand why the resolving wasn't working). However, because iptables doesn't understand hostnames, and is just allowing the ip, you will be able to connect to any website on that ip, if it does have multiple sites. Jan 4, 2011 at 20:59
  • 2
    @Emily, it may work fine, in that the rule is added, but if the serverfault.com IP changes, traffic will not be allowed. Permitting a site like google.com which has hundreds of addresses which are changed frequently would not work at all.
    – Zoredache
    Jan 5, 2011 at 2:17
1

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:

  1. Redirect to the correct URL if they enter the wrong URL (e.g. redirect to stackoverflow.com if they enter www.stackoverflow.com)
  2. Tell your webserver not to serve hosts other than stackoverflow.com
  3. Put the site on a separate IP that nothing else resolves to and only get your webserver to listen on that.
1
  • Hi Phil, I'm not sure I understand what webserver? I don't have a webserver. I'm doing this configuration on my computer.
    – Zenet
    Jan 4, 2011 at 21:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.