Linux – FTPS server in DMZ. Force different IP addresses for passive mode

dmzftplinuxnat;

I'm setting up an FTP server with TLS/SSL encryption (FTPS, not SFTP). The server would be placed in DMZ. This means that it has tho interfaces: one for connections from the company's network and the other (statically NATed to Internet-valid ip address on a border router) for connections from the Internet.

A small ASCII-art to illustrate the setup:

                  |<----------------------------- DMZ --------------------->|

Inet  <---------> |    border router       |  <-------> FTPS server <------->  Internal network
        1.2.3.4   | 1.2.3.4 <NAT> 10.0.1.1 |     10.0.1.1         10.0.2.2

Active mode works well. But for the passive mode, FTP server has to send its IP address to the client. First problem is that the server doesn't know its external address (1.2.3.4), only DMZ-external (10.0.1.1). FTP server software allows to set this address (ForceIpAddress in pure-ftpd), but in this case users from internal network will be unable to work with this FTP (because it will send them 1.2.3.4 instead of 10.0.2.2)

So, the question is if there is a method to choose the IP to send according to client IP address or the interface, the request came to? Note that if a client connects from the Internet, he should get Internet-valid IP address (1.2.3.4) insted of server's internal (10.0.1.1). I'm using pure-ftpd but can change to anything else.

I used two FTP servers on different ports and redirected the request using iptables, but this is not the best way, I think.
Some FTP clients (ex. WinSCP) also allow to force the server's address, but not all of them.

Any options to solve the situation?

Best Answer

The FTP protocol was created when all machines on the internet were globally addressable with a unique IP address. The only reason FTP behind a NAT appliances works now is because the NAT appliance filters FTP traffic and corrects the clear text of the FTP command connection (port 21) to allow for the non-routable addresses involved.

Since you're wrapping your FTP traffic in SSL the NAT appliance cannot read this traffic and so cannot correct for your non-compliant IP addressing. Your solution is going to come from your FTP server.

pure-ftpd has an -N flag that forces "active" mode meaning the FTP server initiates the data transfer (port 20) and will refuse "passive" mode. Passive mode is what FTP clients behind NAT have to use to download from a public FTP site, which you will no longer be compatible with.

proftpd (the best of all posible FTP servers that I've bothered to play with) has a config hack to solve this problem. You can add the "MasqueradeAddress xxx.xxx.xxx.xxx" directive to the config file which will make proftpd tell all clients that the MasqueradeAddress is the ip address of the FTP server. Ensure you have port 20 on this address forwarded with NAT to your FTP server.

As per your note: The "MasqueradeAddress" directive can be used in side the scope of the "VirtualHost" directive, allowing you to provide both the inside access as well as the outside NAT access.