1

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.

Davide DG
  • 21
  • 1
  • 5

2 Answers2

1

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.

Davide DG
  • 21
  • 1
  • 5
0

Is there any way to "inject" the public IP in the PORT command ?

Even if this would be possible this would not help. While the server would probably accept the PORT command with the public IP address it would not be able to connect back to the FTP client using this IP address and port since there is no matching NAT state at the IGW.

If you have two NAT's as in your case (NAT server and IGW) then both of these would need to translate the address in the PORT command and create a state to pass the connection from the server to the newly set IP,port to the IP,port from the original PORT command.

I really recommend to move away from FTP and use alternatives which don't need dynamic data connections like FTP does. Such dynamic connections give you only problems if one of the NAT gateways will not be able to translate the PORT/PASV - maybe because of missing FTP helper or maybe because you are using FTPS (i.e. FTP with TLS) where the NAT gateway will not even be able to see the original IP,port and can also not modify the control connection as needed. Use protocols like SFTP (FTP over SSH) instead which have no problems with NAT since they only use a single TCP connection.

Steffen Ullrich
  • 13,227
  • 27
  • 39
  • I actually found a way to inject the port command: using NETSED. I think IGW is not the problem (I can have working active-ftp connection using a modern ftp server which ignores the private IP in PORT command and only uses the actual tcp port). Yet, the problem you describe (CT state) remains at the NAT server level. You can probably imagine that if I ask this question, I cannot replace this ftp client, not for now at least. – Davide DG Dec 29 '17 at 10:49