A long time ago I was trying to have a transparent proxy setup by using squid, but squid traditionally only knows about http, ftp and https in explicit proxy mode. There is no way to handle non http (for example https) transparently on a traditional setup, so that setup was not what I was looking for.
After looking into TLS SNI and other things, trying even to implement things like that on some tools like socat that would proxify things for squid, I discovered ssl bump on squid3, which just does all the magic I was looking for.
Squid traditionally has several ways of listening to requests, one of which is the explicit proxy port (http_port 3128) and the other typical ones are for transparent proxy, this is indicated by flags:
- transparent: used to intercept server queries and parse http host headers to forward them through squid to the servers
- tproxy: used to spoof outgoing address to that of the client, so that squid is really transparent
Well, none of this allows us to forward https or tcp requests (say for example ssh, imap, ...) for a client that doesn't have explicit proxy support. Unluckily this means that a transparent proxy using this technology nowadays is of no use.
This is where ssl bump comes to the rescue, the old transparent mode of squid, which is currently called intercept, on squid3 has an extra flag: ssl-bump, which has the power of being able to intercept ssl traffic and things like that, allowing squid to cache https webs, but to do this, one has to create a Certificate Authority and the clients must trust this CA that squid uses to issue certificates for the web sites we want to visit.
However ssl-bump can work without issuing these certificates and in this case squid won't mess with https requests, but it will still allow us to do a pretty neat thing, which is to forward all tcp connections from any client (doesn't even have to know what a proxy is) transparently. In this case what squid does is to ask netfilter (iptables) where was the connection that squid is handling supposed to go, and squid makes this connection for the client so that it starts talking to the other end with all the traffic going through squid.
One might ask himself why would he want this traffic on squid, well, you'll have all of squid features, you can control the speed, you get all the typical logs and acls, ...
Of course that if you don't want this you can go with iptables and traffic shaper and that's good as well.
So... you like this idea? Well, then if your distro has squid compiled with ssl support you can read the config section, but if you are (like me) using Debian, you must recompile your squid3 with ssl support. Debian doesn't compile squid3 with ssl support as there are problems between openssl license and squid3 one (squid developers are looking forward to somebody porting the code to gnutls :-)
Rebuilding squid3 with ssl-bump
Well, to rebuild the squid3 package with ssl support you must install the needed packages:
apt-get install fakeroot libssl-dev
apt-get build-dep squid3
There you may find that your distro doesn't have all the packages needed to compile, like for example libecap2-dev, in this case you'll have to apt-get source these packages, compile and install them like we'll do with squid3
And then do a few things as user (we'll use fakeroot which we have just installed) I've tested this using squid3 from Debian testing (the next version, which will be Jessie)
Start with:
apt-get source squid3
And then we'll edit a couple of files on the source, so cd into the source dir and in the debian/control file you must add to the build-depends: libssl-dev and in the debian/rules file you must add this configure options:
--enable-ssl \
--enable-ssl-crtd \
One can then run debchange -i and add something like this on the changelog:
Build with --enable-ssl and --enable-ssl-crtd.
Now the source is ready to build using your favourite command, like for example:
dpkg-buildpackage -rfakeroot
and at last install the needed packages using dpkg -i
Configuration
The main configuration file is stored at /etc/squid3/squid.conf, even though it can be split into separate files. On these files we must set as SSL_ports all the ports for the protocols that we want to allow through squid using an acl like this:
acl SSL_ports port 1935 # rtmp
acl SSL_ports port 5222 # xmpp
acl SSL_ports port 5223 # xmpp over ssl
acl SSL_ports port 5228 # googletalk
acl SSL_ports port 5242 # viber
acl SSL_ports port 4244 # viber
And we'd typically want to define several proxy ports, one for explicit http, another one for http interception (classic transparent proxy) and our ssl-bump port, like this:
http_port 3128
http_port 80 intercept
https_port 3127 intercept ssl-bump generate-host-certificates=off cert=/etc/squid3/squid.pem
acl ssl-bump_port myportname 3127
always_direct allow ssl-bump_port
The direct thing is to force the squid server to send ssl-bump requests directly and not through other caches, as this wouldn't work at all. The certificate is needed even though we won't be using it, just generate one using make-ssl-cert from the ssl-cert package or plain openssl x509 power.
Make sure we have all our client networks listed on our localnet acl and that they are allowed to use the proxy:
acl localnet src 127.0.0.1/32 192.168.0.0/16
http_access allow localnet
Several misc settings like: make sure that ssl-bump doesn't generate certificates for any host at all (just in case), set the language for the errors and allow a good number of filedescriptors so that we don't run out of them
ssl_bump none all
error_default_language es
max_filedescriptors 8192
And that is pretty much what is needed on the squid configuration, of course you can do this and more writing it all in different ways. I have found out that the directory for the ssl certs is not created by default, we must run: /usr/lib/squid3/ssl_crtd -c -s /var/lib/ssl_db
Routing it all through squid
You may be wondering how does all the traffic that we are going to allow through squid get to it. Well, the answer is easy if you have ever configured some kind of transparent proxy or similar, we do it through iptables, in the PREROUTING chain of the nat table we send things to the ssl-bump port or to our transparent proxy port as we like and then we open the ports on which we are serving all this on the INPUT chain of the filter table with something like this which can be loaded with iptables-restore myiptables.cfg:
*nat
:PREROUTING ACCEPT
:POSTROUTING ACCEPT
:OUTPUT ACCEPT
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 1935 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 3389 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 5222 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 5223 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 5228 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 5242 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 4244 -j REDIRECT --to-ports 3127
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport 80 -j REDIRECT --to-ports 80
#This is not for squid but I like these too (local ntp and dns cache)
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p udp --dport ntp -j REDIRECT --to-ports 123
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p tcp --dport domain -j REDIRECT --to-port 53
-A PREROUTING -i eth0 -s 192.168.0.0/16 ! -d 192.168.0.0/16 -p udp --dport domain -j REDIRECT --to-port 53
COMMIT
*filter
:INPUT DROP
:FORWARD DROP
:OUTPUT ACCEPT
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A INPUT -i eth0 -p tcp --dport http -j ACCEPT
-A INPUT -i eth0 -p tcp --dport 3127:3128 -j ACCEPT
-A INPUT -i eth0 -p udp --dport bootps -j ACCEPT
-A INPUT -i eth0 -p udp --dport ntp -j ACCEPT
-A INPUT -i eth0 -p udp --dport domain -j ACCEPT
-A INPUT -i eth0 -p tcp --dport domain -j ACCEPT
COMMIT
I believe that's all, of course this is generally speaking and you'll have to adapt it to fit your needs, but there it is. Just add a dhcp server for convenience and ntp and dns servers so that you don't need to forward those protocols and in order to save more bandwith using the dns server cache and local ntp answers and you're done.
Note that these iptables are dropping all forwarding as in the example the kernel doesn't need to forward anything, squid does it, and for dns and ntp we are using local servers. Of course that if you want to forward some udp traffic, you'll need to add forwarding rules for that.