Squid: Enabling whitelisted FTP proxying using Squid

Having your production servers go through a proxy like Squid for internet access can be an architectural best practice that provides network security as well as caching efficiencies.

In a previous article, I showed how you can enforce whitelists for specific domains when using HTTP/HTTPS.  Now let’s do the same thing for FTP connections, proxying passive FTP connections through Squid, using explicit domain whitelists.

Basic Installation & Configuration

Please see my previous article on how to install, configure, and then validate a basic Squid service on Ubuntu.

Active versus Passive FTP

For this exercise, we are going to enable FTP proxying via passive FTP mode on the client.

Active FTP would require that the remote FTP server initiate the data connection back to the client, which would rarely be desirable in a secure environment sitting behind multiple firewalls.  Passive FTP will allow the squid proxy to initiate all the connections to the remote FTP server host.

This page has nice diagrams explaining the difference between active and passive FTP modes.

Configure FTP Ports and ACL

Assuming you have installed and configured a basic Squid instance for HTTP/HTTPS with whitelisting as described in my previous article, you just need to make slight modifications to the “/etc/squid3/squid.conf” file in order to enable FTP proxying.

Right under the line which defines the ‘SSL_ports’, add another line for the FTP_ports as shown below.

# SSL_ports will already be defined
acl SSL_ports port 443
# add these FTP port definitions
acl FTP_ports port 21 1025-65535

I’m sure you will recognize port 21 as relevant to FTP, but the port range 1025-65535 is also necessary because with passive FTP the remote FTP server arbitrarily assigns a port for your data connection back to the remote server.

The next modification is to allow ‘CONNECT’ not just for the SSL_ports, but also the FTP_ports, by modifying the line as shown below:

# CONNECT not just for SSL ports, but also FTP ports
#http_access deny CONNECT !SSL_ports
http_access deny CONNECT !SSL_ports !FTP_ports

Then, you need to add the FTP hostname and IP addresses to the whitelist.  In this example, we are going to configure Squid to proxy FTP connections to the public FTP site, ‘ftp.ubuntu.com’.

Doing an nslookup on the host ‘ftp.ubuntu.com’ as shown below, it is clear that there is a cluster of IPs servicing this site.

$ nslookup ftp.ubuntu.com
Server:		127.0.0.1
Address:	127.0.0.1#53

Non-authoritative answer:
Name:	ftp.ubuntu.com
Address: 91.189.88.149
Name:	ftp.ubuntu.com
Address: 91.189.88.161
Name:	ftp.ubuntu.com
Address: 91.189.88.162
Name:	ftp.ubuntu.com
Address: 91.189.88.152

This leads us to define the whitelist in squid.conf as shown below:

# enable both FTP hostname and IPs
acl whitelist dstdomain ftp.ubuntu.com 91.189.88.149 91.189.88.152 91.189.88.161 91.189.88.162
http_access allow whitelist

The reason why we need the IP addresses as well is because the remote FTP server will usually send back the data connection address in the format ‘<hostIP>:<randomPort>’ (instead of <hostName>:<randomPort>).

Finally, we make sure that the FTP protocol is allowed by adding the following lines right below the whitelist definitions and right before the last lines denying all other traffic.

# add these lines to allow FTP
acl ftp proto FTP 
http_access allow ftp 


# these lines below already existed 
http_access allow localhost 
http_access deny all

Now reload the squid configuration

$ sudo service squid3 reload

Validate with FTP client

Validation can be done with any modern FTP client that supports proxy access and passive mode.  Filezilla and Firefox are both good options, but I want to use a console based client.  Let’s use lftp that is available from the Ubuntu repositories.

The commands below will install lftp and then connect to ftp.ubuntu.com via the squid proxy and do a simple directory listing.  Replace the highlighted IP below with that of your own Squid server.

$ sudo apt-get update
$ sudo apt-get install lftp -y

$ lftp -e "set ftp:proxy http://192.168.2.131:3128;set ftp:use-hftp no;set xfer:clobber on;set -a;open ftp.ubuntu.com;ls;quit" -u anonymous,guest -d

If you were tailing “/var/log/squid3/access.log” on the Squid host you should see output similar to below showing the control connection to port 21 being open/closed, and then a data connection on port 20028 (randomly decided by ftp.ubuntu.com server).

1516909421.330 150 192.168.2.216 TCP_MISS/200 64 CONNECT 91.189.88.162:20028 - HIER_DIRECT/91.189.88.162 -

1516909421.406 750 192.168.2.216 TCP_MISS/200 308 CONNECT ftp.ubuntu.com:21 - HIER_DIRECT/91.189.88.162 -

Now let’s test a file download from the Ubuntu ftp site.  There is a file named “InRelease” in the xenial downloads folder.

$ lftp -e "set ftp:proxy http://192.168.2.131:3128;set ftp:use-hftp no;set xfer:clobber on;set -a;open ftp.ubuntu.com;ls;get /ubuntu/dists/xenial/InRelease;quit" -u anonymous,guest -d

Now there will be three lines in the Squid access.log, the last line indicating the control connection on port 21 and the other two are data connections for the file listing and then the 246846 byte file download.

1516909336.749 151 192.168.2.216 TCP_MISS/200 64 CONNECT 91.189.88.162:45510 - HIER_DIRECT/91.189.88.162 -
1516909337.552 434 192.168.2.216 TCP_MISS/200 246846 CONNECT 91.189.88.162:19057 - HIER_DIRECT/91.189.88.162 - 

1516909337.628 1554 192.168.2.216 TCP_MISS/200 539 CONNECT ftp.ubuntu.com:21 - HIER_DIRECT/91.189.88.162 -

 

 

 

REFERENCES

https://unix.stackexchange.com/questions/15484/connecting-to-ftp-sites-via-squid

http://servercomputing.blogspot.com/2011/12/how-to-enable-ftp-access-through-squid.html

https://serverfault.com/questions/427655/squid-and-ftp-connections

https://www.experts-exchange.com/questions/28517229/FTP-through-proxy-problems-Squid-centos.html

https://stackoverflow.com/questions/1699145/what-is-the-difference-between-active-and-passive-ftp (active vs. passive with diagrams)

http://slacksite.com/other/ftp.html (explanation of active vs passive)