Re: FTP hangs with Firewalls/NAT

Giganews Newsgroups
Subject: Re: FTP hangs with Firewalls/NAT
Posted by:  Remy Lebeau (TeamB) (
Date: Thu, 1 Dec 2005

"DeXter" <gricar…> wrote in message

> Since the FTP server I'm trying reach is behind a NAT, LIP
> contains its local address (ie., so the LPasvCl
> client will try to connect to an incorrect address.

The FTP server is responsible for sending the proper IP in the PASV
response.  If a router is present, the FTP server must be configured to send
the router's public IP address (TIdFTPServer in Indy 10 has an OnPASVReply
event for that).  Or the router has to be smart enough to recognize FTP
commands to that is can automatically update the PASV response accordingly.
It is not TIdFTP's responsibility to validate the IP that is receives.  It
must use the IP as-is since that is what the server told it to use.

> I've corrected this by changing
>    LPasvCl.Host := LIP;
> by
>    LPasvCl.Host := Host;
> which contains the original an correct IP address.

Perhaps, but doing so will then prevent Server<->Server transfers from
working correctly.  The problem for this issue is on the FTP server's side,
not in TIdFTP.

> Also, if there is a problem with this connection (an actually there is,
> because the Ip is incorrect), the  FinalizeDataOperation; is called in the
> finally block. That method hangs the FTP, so I had to moveit before the
> finally block.

Doing so will leak resources if an error occurs.  If FinalizeDataOperation()
is blocking, then you should find the cause of the actual blockage, not move
the entire method call to another location.  My guess would be that the
blockage is in the GetResponse() calls at the end of
FinalizeDataOperation().  Which actually makes sense that they get called
because the server is required to send a response if the transfer fails,
including if the data connection was never established.  Server's are
required to have a timeout when waiting for an incoming PASV connection, for
exactly this reason.  If the blockage is in the GetResponse() calls, then
the server is not sending a failure response back like it is supposed to.

> 2) When you set Passive:=False and your client is behind a firewall and
> you make a List command:
> Here, since you are behind a firewall and you are listening a port that
> server cannot reach, the LPortSv.Listen stays in an infinite loop, only
> broken by an abort command.

You need to send the router's public IP in the PORT command to the server so
that it knows where it can connect.  To do that, set the TIdFTP's ExternalIP
property to the router's public IP before doing anything that requires a
data connection to be established (List(), Stat(), Get(), Put(), etc).



In response to

FTP hangs with Firewalls/NAT posted by DeXter on Thu, 1 Dec 2005