FTP hangs with Firewalls/NAT

Giganews Newsgroups
Subject: FTP hangs with Firewalls/NAT
Posted by:  DeXter (gricar…@cybelesoft.com)
Date: Thu, 1 Dec 2005

I've found two problems when working behind firewalls:

1) When you set Passive:=True, there is what it seems an error  in bellow
code:

    if FPassive then begin
      SendPret(ACommand);
      //PASV or EPSV
      if FUsingExtDataPort then begin
        SendEPassive(LIP, LPort);
      end else begin
        SendPassive(LIP, LPort);
      end;
      FDataChannel := TIdTCPClient.Create(nil);
      LPasvCl := TIdTCPClient(FDataChannel);
      try
        InitDataChannel;

        LPasvCl.Host := LIP;
        LPasvCl.Port := LPort;

Since the FTP server I'm trying reach is behind a NAT, LIP contains its
local address (ie. 192.168.0.17), so the LPasvCl client will try to connect
to an incorrect address.
I've corrected this by changing
    LPasvCl.Host := LIP;
by
    LPasvCl.Host := Host;
which contains the original an correct IP address.

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.

2) When you set Passive:=False and your client is behind a firewall  and you
make a List command:

      LPortSv := TIdSimpleServer(FDataChannel);
      try
        InitDataChannel;

        LPortSv.BoundIP := (Self.IOHandler as
TIdIOHandlerSocket).Binding.IP;
        LPortSv.BoundPort := FDataPort;
        LPortSv.BoundPortMin := FDataPortMin;
        LPortSv.BoundPortMax := FDataPortMax;

        if Assigned(FOnDataChannelCreate) then begin
          OnDataChannelCreate(Self, FDataChannel);
        end;

        LPortSv.BeginListen;
        if FUsingExtDataPort then begin
          SendEPort(LPortSv.Binding);
        end else begin
          SendPort(LPortSv.Binding);
        end;
        if AResume then begin
          SendCmd('REST ' + Sys.IntToStr(ADest.Position), [350]);  {do not
localize}
        end;
        SendCmd(ACommand, [125, 150, 154]); //APR: Ericsson Switch FTP);

        LPortSv.Listen;
        if FUsingSFTP and (FDataPortProtection = ftpdpsPrivate) then begin
          TIdSSLIOHandlerSocketBase(FDataChannel.IOHandler).PassThrough :=
False;
        end;

Here, since you are behind a firewall and you are listening a port that the
server cannot reach, the LPortSv.Listen stays in an infinite loop, only
broken by an abort command. This doesn't sound correct. I tried with ther
FTP clients (ie. FlashXP) and they times out. You don't need to abort the
List command.
I had to Timeout parameter to TIdSimpleServer.Listen method, to avoid the
infinite loop.

Remy, I'm not sure if what I did is correct, but at least it is working
better now. Can you advise please?

Thanks,
Gustavo Ricardi

Replies