FTP Active mode and NAT with private addressing (AWS)

amazon-web-servicesftplinux-networkingnat;

this is quite related to this question regarding GCP, but on AWS, and also trying to solve it with a different approach.

I have an FTP client trying to connect in ftp active mode to some ftp servers located on the Internet.
The FTP client has private address, and it is behind a NAT instance server (not NAT Gateway)

This NAT-server has private address too, and is itself behind the VPC Internet GW.

Diagram:

FTP client (10.60.0.0/24) –> NAT server (10.254.254.0/24) –> IGW –> Internet –> Firewall/NAT –> FTP Servers

NAT Server is AWS NAT Linux (kernel 4.9) with masquerading turned on.

With Active-FTP (port mode), this is not working.

I already activated CT FTP helper (nf_nat_ftp) and its triggering iptables rule:

iptables -A PREROUTING -t raw -p tcp --sport 1024: --dport 21 -j CT --helper ftp

and I can see that the "PORT" command is being correctly translated from the private IP address of FTP client to the private IP of the NAT server.

Unfortunately, this isn't enough, because the FTP Server is receiving an FTP "PORT" command still with a private address (the one of the NAT server).

So the ftp data connection, initiated from the ftp server, of course never reaches back.

I cannot, at least for now, "replace" the ftp client (it's part of a legacy application).

Is there any way to "inject" the public IP in the PORT command ?
Some ideas came to my mind, but I could not find proofs whether they are realistic or I'm wasting my time:

  1. creating a "fake" interface on the nat server with the public ip address, and selectively enabling/disabling CT helper to modify the PORT command. I have troubles with the correct routing for this, though (let alone convincing myself it's worth trying)

  2. modifying the nf_nat_ftp helper module with hard-coded public IP (so uglyyy!)

  3. modifying the port command on the ftp client (it's a Windows machine), don't know if a driver/tool already exists for that purpose

  4. brute-patching the ftp client (might be the most realistic way…?)

About option 3: I tried NETSED, which actually can change the PORT command, but it seems to mess up the nat for the ftp client! 🙁

Other solutions are of course welcome!

Thank you.

Best Answer

Trying to answer my own question on a limited use-case

The limit is: only 1 ftp client in active mode behind the nat server (it does not work with masquerading)

  • ftp client: 10.60.10.11
  • nat server: 10.254.254.203
  • public ip : 1.2.3.4

First, fire up netsed on the nat server, local port 21, converting all packets containing "PORT 10,60,10,11," to "PORT 1,2,3,4," (thus leaving port numbers unchanged):

./netsed tcp 21 0 0 s/PORT%2010,60,10,11,/PORT%201,2,3,4,

Second, redirect traffic from ftp client to netsed:

iptables -t nat -A PREROUTING -p tcp --dport 21 -j REDIRECT --to 21

This will make the ftp server "happy" and it will effectively try to open a new connection from port 20 to the public IP. IGW will let pass, but the NAT server does not know how to handle the connection (it's not in CT, it's a new connection).

So, as ugly as it may be, now forward all incoming traffic from port 20 to the internal FTP client:

iptables -t nat -A PREROUTING -p tcp -d 10.254.254.203 --sport 20 --dport 1024:65535 -j DNAT --to-destination 10.60.10.11:1024-65535

This is working!!

But, a part from being a hack, it seems it is limited to only 1 ftp-client.

Thank @Steffen for pointing out that CT state was not set.