FXP - FTP transfers from server to server

Every so often I get a question from someone who wants to transfer files between two FTP servers.  In order to do so, they usually have to connect to server 1, download the files, and then connect to server 2 and upload the files.  The process could go much sooner if they could eliminate the extra transfers and just copy the files directly from server 1 to server 2.  It turns out this is possible, and is in fact mentioned in the FTP spec (RFC 959), but most people don't realize it.  Also most servers don't allow it by default, for security reasons.

FXP, aka site-to-site transfer, aka server-to-server transfer is really just a sneaky trick of the FTP protocol itself.  Here's how FXP works:

  1. Create a connection to FTP server 1, and another connection to FTP server 2. 
  2. On FTP server 1, enter passive mode (data connections will be incoming), and make a note of the servers response to the PASV command (what ip the server will be listening on, and on what port). 
  3. On server 2, send a PORT command (data connections will be outgoing), such that the port command data corresponds to the data in FTP server 1's reply to the PASV command gathered in step 2. 
  4. Finally, send the STOR command to ftp server 1, and the RETR command to FTP server 2.  The data connection will be made between those two servers, and when the transfer is complete the client will be notified by

Here's how you can do this with two instances of the IPWorks FTP component:

   1:      public void FXP()
   2:      {
   3:        //FXP, aka site-to-site or server-to-server transfers
   4:        //not commonly supported by FTP servers by default, for
   5:        //security reasons
   6:   
   7:        string[] portdata = null;
   8:        Ftp ftpA = new Ftp();
   9:        ftpA.Timeout = 5;
  10:        ftpA.OnPITrail += new Ftp.OnPITrailHandler(delegate(object sender, FtpPITrailEventArgs e)
  11:        {
  12:          if (e.Message.StartsWith("227")) //response to PASV
  13:          {
  14:            string portparams = e.Message.Substring(e.Message.IndexOf("(") + 1);
  15:            portparams = portparams.Remove(portparams.IndexOf(")"));
  16:            portdata = portparams.Split(new char[] { ',' });
  17:          }
  18:        });
  19:        ftpA.RemoteHost = "serverA";
  20:        ftpA.User = "test";
  21:        ftpA.Password = "password";
  22:        ftpA.Passive = true;
  23:        ftpA.Logon();
  24:        ftpA.Command = "PASV";
  25:        //if this reply was 200 OK, then the server will allow the site to site transfer.
  26:   
  27:        //now we know the port number that server A is listening on (portparams),
  28:        //so start a retriever on server B:
  29:        ThreadPool.QueueUserWorkItem(new WaitCallback(FTPRetriever), portdata);
  30:   
  31:        //start the sender on server A:
  32:        ftpA.Command = "STOR uploaded.txt\r\n"; //the file to create on server 1
  33:   
  34:        //done..disconnect
  35:        ftpA.Logoff();
  36:      }
  37:   
  38:      static void FTPRetriever(object parameter)
  39:      {
  40:        string[] portdata = (string[])parameter;
  41:        Ftp ftpB = new Ftp();
  42:        ftpB.Timeout = 5;
  43:        ftpB.RemoteHost = "serverB";
  44:        ftpB.User = "test";
  45:        ftpB.Password = "mypassword";
  46:        ftpB.Passive = false;
  47:        ftpB.Logon();
  48:        ftpB.RemotePath = "destinationfolder/";
  49:        ftpB.ListDirectory();
  50:   
  51:        ftpB.Command = "PORT " + portdata[0] + "," + portdata[1] + "," + portdata[2] + "," + 
  52:                                     portdata[3] + "," + portdata[4] + "," + portdata[5];
  53:        ftpB.Command = "RETR uploaded.txt"; //the file to get from server A
  54:        ftpB.Logoff();
  55:      }

 

There you have it, a pretty straight forward process.  ftpA connects to server A and sends the command needed to create an incoming data transfer connection and start sending a file called uploaded.txt.  ftpB connects to server B and sends the commands needed to create an outgoing data transfer connection (to server A) and receive the file uploaded.txt.

Technorati Tags: , ,

Print | posted on Thursday, May 15, 2008 12:02 PM

Feedback

# Mr

Left by Raj Hasan at 12/5/2010 10:39 AM
Gravatar Thanks so much for this script. If it works, will save my tons of time. I am going to use it now. Will post again. If it works for me.

Your comment:





 
 

Copyright © Lance Robinson

Design by Bartosz Brzezinski

Design by Phil Haack Based On A Design By Bartosz Brzezinski