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.


Solution 1:

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.

Solution 2:

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.