Saturday, July 2, 2016

Transparent Proxy with CentOS 7, Squid, and Firewalld

Squid is fairly easy to set up.  The firewall took me a little longer, however, in CentOS 7 (IPTABLES isn't the default firewall any more, and instead, a new player is in the ring, firewalld).  This nice little tool can be much more user friendly, if you know what you are doing.  I started out here intending to place Squid (a proxy server) in between my internal network and the outside world for two reasons :
  • I wanted to prevent requests to pages or sites that were not kid-friendly
  • I wanted to cache some of the most heavily used images and sites to speed up requests and page loads
It did take me a bit to figure it out, but I managed.

The first step is to ensure the interfaces fall into the right zones.  Trust me on this, it's pretty important.  I found (before I did this) that often on boot up, DNS would fail to operate until I stopped and started the firewalld service after the initial boot.  Open up each of the /etc/sysconfig/network-scripts/if-cfg* interface files (safe to skip the lo* interface, obviously), and add a single line to them :
Options here are "work", "trusted", "internal", and "public".  Pick the right interfaces - this is vital.

Once you have that in place, enable IP forwarding :
    echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
The third step was enabling masquerading for my internal house guests, and to allow established connections.  This was done using :
    firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -o enp1s0 -j MASQUERADE
    firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i enp1s0 -o enp2s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
Once that is working I wanted to punch a couple of holes through the firewall :
    firewall-cmd --zone=external --add-service=http --permanent
    firewall-cmd --zone=external --add-service=https --permanent
    firewall-cmd --zone=external --add-rich-rule="rule family=\"ipv4\" source address=\"\" port protocol=\"tcp\" port=\"22\" accept"
Note that mine shows that I am only accepting SSH connections from a specific IP address - this is to prevent those jackass hackers from trying to brute force there way in through SSH.  If you need, it could have been a simple "--add-service=ssh" instead.

And lastly, you HAVE to make sure to intercept HTTP connections from the inside of the network, heading to the outside of the network.  I didn't want Squid responding to internal-to-internal connections, possibly getting in the way of some of the video feeds going across the network.
    firewall-cmd --zone=trusted --permanent --add-rich-rule=rule family="ipv4" source address="" destination address="" invert="True" forward-port port="80" to-port="3128" to-addr="" protocol="tcp"
The above rule will fire off IF a request comes from an internal IP address (, that is heading to for port 80 (HTTP).  It reroutes that to the local port 3128 (which is where squid is listening), and Squid handles the request from there on out (allowing the cache or block).  However, since we added the "destination address" with a following "invert", we are going to ignore anything that is NOT going to the outside world.


It's fairly easy - just install squid (yum install squid), open the "/etc/squid/squid.conf" file, and locate the line that reads "http_port 3128" .  Add a space followed by "intercept", e.g. "http_port 3128 intercept", and Squid will now act as a transparent proxy.

Since I also wanted to block some sites, I threw in a list of server names into a file called "/etc/squid/bad-sites.acl", e.g. :
and in the squid.conf file, I added the following at the top :
    acl bad_sites dstdomain "/etc/squid/bad-sites.acl"
Then, I located a line that began with "INSERT YOUR OWN RULE(S) HERE", and added :
    http_access deny bad_sites
After the comment block for that.  Restart it, and it will be blocking the sites listed in the bad-sites.acl!  Congratulations on setting up a transparent proxy!

No comments:

Post a Comment