I found that it was a real mess to set up a FTP server in a DMZ, behind a firewall Cisco Asa (501 model with IOS version 7.0).
The FTP server is on the DMZ area, and therefore I natted a public IP to the private IP in the DMZ subnet of this server.
static (dmz,outside) <public IP> <private_IP> netmask 255.255.255.255
Doing so, I expect that my FTP server (like Vsftpd on Linux) to be reachable within its public IP, from the Asa external interface.
Choosing a FTP transfer mode
Before going further, let’s recall the two modes in which the FTP protocol can work :
- active mode : this is the historical mode, but should be considered obsolete now because of the numerous issues it contains. In this mode, after the client initiate the communication on the port 21 (command chanel), the server initiate the data transfert chanel from its port 20 toward a port specified by the client. It causes two big problems :
- the client must configure its firewaling to allow incomming traffic on this port. In the real life, this is most likely to be like allowing the 1024-65535 range port for incoming traffic. Not really secure, isn’t it ?
- if the client is behind a NAT, it won’t work ! As the server initiate the connection, the router does not have any entry for the flow in its NAT table. It will just drop the connexion.
- passive mode : the difference here is that the server chooses on what port the data transfert will be operated. The port is given to the client when this one initiate the communication. Actually, the server never initiate any connexion, so the name “passive”. The only thing to do on the server side is to set the right firewall rule to allow the server ports. The client then initiate the transfert on the given port. It solves the client side firewalling problem, because the firewall will see it as outbound traffic. With correct rules, especially if the firewall is statefull, this is an easy thing.
Configuring the passive mode on the server
So, is the passive mode the end of all problems ?
By default, the FTP server will be listening on its netword interface and answer to the FTP requests with its private IP, if, like probably in many case, the FTP server is located on a DMZ network.
In such a case, the client gets a private IP to connect with… and can never reach the server properly.
To workaround this problem, most of FTP servers can be configured to answer with there public IP.
With VSFTP, this is a line like :
pasv_address = $public_IP
There another two issues for that :
- the server won’t be reachable anymore within its private IP, for instance from the local subnet
- the Cisco Asa firewall drops the traffic
Cisco Asa issue
The Asa log file shows :
FTP port command different address: $IP_addr ($IP_addr2) to $IP_addr_3 on interface int_name
The explanation from the cisco website :
A client issued an FTP port command and supplied an address other than the address used in the connection. This error message is indicative
of an attempt to avert the site’s security policy. For example, one might attempt to hijack an FTP session by changing the packet on the way, and putting
different source information instead of the correct source information. The PIX Firewall drops the packet, terminates the connection, and logs the event.
In the error message displayed, the IP address in parentheses is the address from the PORT command.
Well, as there is nothing to do against this behaviour, I won’t use the pasv_address option.
Private IP issue
So, for now we stick with a server sending its private IP address in any case. That solves any issue in the local subnet, but is it possible to do anything for external clients which needs to get a public IP ?
Actually, and this is really not a satisfying answer, it depends on the client. Most of the FTP client must have the some options to workaround this issue, but not all.
Let’s check how it is with a few FTP clients.
Basic FTP command line client (Linux)
$ ftp X.X.X.X ftp> dir 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. -rw-rw-r-- 1 102 1001 21 Aug 16 10:53 test 226 Directory send OK.
Humm… it is working, but it shouldn’t as my server is configured for passive mode.
Let’s see what is going on with Wireshark… Two packets are interesting :
28 35 192.168.1.2 X.X.X.X FTP Request: PORT 192,168,1,2,173,87 29 36 X.X.X.X 192.168.1.2 FTP Response: 200 PORT command successful. Consider using PASV.
From the client, we have a PORT request, which shows that our client is connecting in active mode.
Surprise, the server replies ! And says successful, even if the IP given is a private one. That should not work and, if any response, not go out of the external firewall…
Note : (192,168,1,2,173,87) is the FTP way to manage IPs and port. The IP is simply given by the four first numbers : 192,168,1,2 <=> 192.168.1.2.
The 2 last ones gives you the port number with this formula : 173,87 => 173 x 256 + 87 = port n°44375
Anyway, let’s try the passive mode :
ftp> passive on Passive mode on. ftp> dir 227 Entering Passive Mode (10,1,1,1,15,195) receive aborted waiting for remote to finish abort
We tried to switch to passive mode. The server gaves its IP, but its private one (192.168.10.1). The client trying to reach this address can’t and falls in timeout (I killed it, no more patience :) ) .
Now, let’s summarize.
Using the ftp basic client, we can’t go through in passive mode. We get a private IP and we have no workaround.
The active mode works, but it is thanks to the behaviour of VSFTP.
A look on the man page of VSFTP gives some answers : the
directive, set to YES by default, allow the PORT command from the client even in passive mode. So, we could add in the vsftd.conf configuration file :
After that the server will answer
550 Permission denied
when a PORT command is issued. At the end, I won’t set this, because such a behaviour is actually nice.
I still wonder how VSFTP could get the public IP when the PORT command send the private IP. I guess, and it would be a smart behaviour, that the program checks the underlying protocol layers and takes the right IP from the IP header… I will have it confirmed and update this post.
This Gnome FTP client behave like the ftp command line client in passive mode : it falls into timeout.
It doesn’t try by default to fail over active mode.
You can configure either active mode or ignoring the passive command IP in the options :
Filezilla has the most interesting behaviour. When the standard passive mode fails, it is able to fail over by using active mode or using the public IP seen from the server.
This can be configured in the connexion options :
When Filezilla uses the public IP address instead of the transmitted one :
PASV 227 Entering Passive Mode (10,1,1,1,15,209) LIST 150 Here comes the directory listing. 226 Directory send OK.
When it is configured to switch to active mode :
PASV 227 Entering Passive Mode (10,1,1,1,15,179) PORT 192,168,1,2,130,1 200 PORT command successful. Consider using PASV. LIST 150 Here comes the directory listing. 226 Directory send OK.
I could not reach the point where I can be 100% sure that it will work in all configurations. The best I could do is a series of small fixes to get the best compromise as possible.
I guess that using VSFTD as a server and recomanding a good client as Filezilla will work pretty well – and that won’t be a big deal to get to such a configuration.
If anyone has some better ideas, or see I fooled somewhere before my conclusion, please let me know.
But anyway, really, FTP sucks. It is anoying that the use of this protocol is still required by some companies.