4

Here's my network configuration:

My network configuration http://daveden.files.wordpress.com/2013/05/network-configuration.png

The proxy server is running Ubuntu with Squid on port 3128 and DansGuardian on port 8080.

I'd like to force all clients to use the proxy server - specifically, port 8080 - for any HTTP/HTTPS access.

However, I don't want to transparently redirect because that doesn't work for HTTPS. I don't mind configuring each client, and I don't mind that each client knows it's using a proxy server. I just don't want the clients to be able to surf the web without the proxy settings.

How do I do this? Can I just drop packets if the client isn't configured to use the proxy server on port 8080?

I tried using iptables to drop packets that had a dport other than 8080, but that rejected too much I think and I could no longer access anything.

EDIT

I re-wrote this question so that it's not iptables specific, but I am not against using iptables at all. I just want to attract a wider range of possible solutions.

EDIT 2

I think I may have given some the wrong impression. Just to be clear, I'm not at all interested in filtering HTTPS traffic (i.e., looking taking packets apart at the proxy and inspecting the contents). I'm more interested in blocking sites with DansGuardian, whether it's over HTTP or HTTPS (by looking at the destination of the packets).

EDIT 3

Based off of Alexandru-Florin Vintil's suggestion below, here's what I'm currently doing:

# Redirect HTTP traffic to port 8080 (DansGuardian)
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 8080

Check TCP and UDP traffic against whitelist

iptables -A FORWARD -i eth1 -p tcp --dport 443 -j whitelist iptables -A FORWARD -i eth1 -p udp --dport 443 -j whitelist

Drop all other HTTPS traffic

iptables -A FORWARD -i eth1 -p tcp --dport 443 -j DROP iptables -A FORWARD -i eth1 -p udp --dport 443 -j DROP

Drop all traffic aimed straight at the proxy

iptables -A FORWARD -i eth1 -p tcp --dport 3128 -j DROP iptables -A FORWARD -i eth1 -p udp --dport 3128 -j DROP iptables -A FORWARD -i eth1 -p tcp --dport 8080 -j DROP iptables -A FORWARD -i eth1 -p udp --dport 8080 -j DROP

In a nutshell, redirect HTTP traffic to port 8080, drop all HTTPS traffic that isn't whitelisted (in a separate chain), and drop all traffic that explicitly uses the proxy. Without the last rule, a client can access any website using HTTPS as long as they configure their browser to use the proxy, because then the destination port is 8080 and not 443. So even dropping all traffic bound to 443 doesn't block HTTPS altogether.

6 Answers6

4

Whenever you see that something that should work isn't working, you need to ask if there is some other factor involved that you are not seeing. The rule

sudo iptables -A INPUT -p tcp ! --dport 8080 -j REJECT

Looks like it should work, but you have appended it to the INPUT chain, so it is probably circumvented by a previous rule in the chain. This rule should be adequate by itself, as the INPUT chain is the first chain that incoming packets hit. If they are REJECTed at the INPUT chain, they never get to the FORWARD or OUTPUT chains. Of course, this rule will block everything TCP that is not destined for port 8080, which is probably not what you really want in the end unless the proxy at 8080 is the only service on the machine and you only log in from the console.

So the first thing to do is to list the rules and look for what might be causing the packets to pass:

sudo iptables -L

If your firewall is reverse NATting then you should also list the NAT table.

sudo iptables -L -t nat

Afterwards, try the putting the same rule at the beginning of the chain:

sudo iptables -I INPUT -p tcp ! --dport 8080 -j REJECT

and see if that doesn't solve the problem, or at least give you more confidence that you understand how iptables works so that you can complete your rule set. If you are working on this host from remote, my suggestion will cut you off, so you should do this only from the console. To work safely from remote see my colleague Eli Rosencruft's post about tweaking firewalls from remote.

3

Standard

A separate (user-defined) chain might help.

# create a chain just for user 100 (192.168.1.100)
iptables -N custom_user_100

# redirect all traffic FROM user 100 to custom chain
iptables -A INPUT -p tcp -s 192.168.1.100 -j custom_user_100

# return from user chain for valid traffic, drop all other
iptables -A custom_user_100 -p tcp --dport 8080 -j RETURN
iptables -A custom_user_100 -j DROP

So - what this does is redirect any traffic FROM 192.168.1.100 into a custom chain. This custom (user-defined) chain merely returns if a valid match is found (traffic destined for port 8080). All other non-matching traffic that doesn't result in a return from the chain is dropped.

Later you can view the tables statistics to verify this is what happened:

iptables -L -v -n

Forwarding

Now, on the off-chance you are processing forwarding traffic, there will be a different set of rules - but the idea of using a custom (user-defined) chain is the same. I like to refer to the diagram at this link: http://www.csie.ntu.edu.tw/~b93070/CNL/v4.0/CNLv4.0.files/Page697.htm when trying to understand the flow of packets.

In this case you might want to do something like the following:

# create a chain just for user 100 (192.168.1.100)
iptables -N custom_user_100

# redirect all traffic FROM user 100 to custom chain
iptables -A FORWARD -p tcp -s 192.168.1.100 -j custom_user_100

# return from user chain for valid traffic, drop all other
iptables -A custom_user_100 -p tcp --dport 8080 -j RETURN
iptables -A custom_user_100 -j DROP

This is identical to the first except that the rule that was applied to the INPUT chain is, instead, applied to the FORWARD chain.

Update 2013-05-24

I've re-read your question. So will start over.

Let's assume your "proxy" is actually a router. That is - it is passing all packets from one interface to another - perhaps using NAT. This means that all packets of interest are flowing through the FORWARD chain.

Next: you say you will configure all clients using port 8080 to hit the proxy itself. Fine. This means that all those packets will enter the "proxy" via the INPUT chain.

So: you just want to prevent anybody from going out port 8080 on the FORWARD chain.

iptables -A FORWARD -p tcp --dport 8080 -j REJECT

This rule will ensure anything that is to be forwarded to a destination port of 8080 will be rejected (an ICMP packet will be sent to the client that attempted to pass the packet through the proxy).

After you implement this rule it is VITAL that you test this by attempting to make such an forbidden connection - then you list the rules by typing:

iptables -L -v -n |grep 8080

and ensure the counter has increased. If not then something is wrong with the router configuration.

PP.
  • 3,606
2

My 2 cents:

Regarding HTTP: Having a firewall transparently forward port 80 traffic to a proxy/filter is the simplest way of doing things. No need for client configuration, + you can exempt any host/subnet from using the proxy without the need for client reconfiguration. This is the only way you can be assured that everything that is supposed to pass through proxy, is.

Any method other than blocking all outgoing HTTPS 443 traffic and allowing only a subset of sites based on ip allowed to outgoing port 443 won't work as expected. HTTPS' secure protocol is designed (a few flaws aside) to prevent Man-In-The-Middle attacks (proxies ARE "legal" MITM). This way, HTTPS is allowed to do what it was designed to do. If however, you want to IGNORE HTTPS, you should setup your squid to use DIRECT and not use CONNECT (tapping), but even if this is the case, you still may run into problematic websites with mixed HTTP/HTTPS parts. This way, your Squid proxy will manage HTTPS as well. This should also be reflected in transparent forwarding part of your firewall.

1

First read a bit of iptables documentation - specifically you at least need to know what chains in what tables a packet will enter (take a look here: http://www.iptables.info/en/structure-of-iptables.html).

You'll have to balance between two things: your goal to force everyone to use proxy and everybody's convenience. On one hand you can disallow forwarding of any packets at all (you can even disable ip_forwarding flag in the kernel). This way local computers will be able to access the internet only by your proxy server. But even that won't stop everyone from using a tunneled connection through your http proxy (and it's even easier with https ones). So you won't be able to fully monitor or limit internet usage.

On the other hand you can take an even softer approach: just limit outgoing traffic to port 80. In that case the software which doesn't use http (e.g. skype) won't have to tunnel traffic in http and the good-behaving clients will have all the benefits of a local http cache (faster access to sites).

Your current configuration looks like the first option above. But you have the unnecessary ACCEPTing rules in FORWARD chain. You don't want the router to forward any packets. Local computers connect to your proxy (packets go through INPUT chain) and not to the remote hosts. With your current setup someone could find a proxy listening on port 8080 anywhere on the internet and use that instead of your proxy.

skarap
  • 761
1

If you don't want your clients just accessing http{s} sites without the proxy, than you may just DROP or REJECT forwarded packets to ports 80 and 443:

IPTABLES -I FORWARD -i eth1 -p tcp -m multiport --dports 80,443 -j REJECT

Where eth1 is your internal interface. Doing this way you won't have to mess around with other ports/access.

fboaventura
  • 1,163
0

Personally, I like to set the default policies for the INPUT and FORWARD chain to DROP

iptables -P INOUT DROP
iptables -P FORWARD DROP

Then allow only the traffic I want - this way, I find less surprises and am very certain only what I allow is going where I direct it.

John Kloian
  • 142
  • 3