/// <summary> /// Opens a FXP PASV connection between the source FTP Server and the destination FTP Server /// </summary> /// <param name="remoteClient">FtpClient instance of the destination FTP Server</param> /// <returns>A data stream ready to be used</returns> private FtpFxpSession OpenPassiveFXPConnection(FtpClient remoteClient) { FtpReply reply; Match m; FtpClient sourceClient = null; FtpClient destinationClient = null; if (EnableThreadSafeDataConnections) { sourceClient = CloneConnection(); sourceClient._AutoDispose = true; sourceClient.CopyStateFlags(this); sourceClient.Connect(); sourceClient.SetWorkingDirectory(GetWorkingDirectory()); } else { sourceClient = this; } if (remoteClient.EnableThreadSafeDataConnections) { destinationClient = remoteClient.CloneConnection(); destinationClient._AutoDispose = true; destinationClient.CopyStateFlags(remoteClient); destinationClient.Connect(); destinationClient.SetWorkingDirectory(destinationClient.GetWorkingDirectory()); } else { destinationClient = remoteClient; } sourceClient.SetDataType(sourceClient.FXPDataType); destinationClient.SetDataType(destinationClient.FXPDataType); // send PASV command to destination FTP server to get passive port to be used from source FTP server if (!(reply = destinationClient.Execute("PASV")).Success) { throw new FtpCommandException(reply); } m = Regex.Match(reply.Message, @"(?<quad1>\d+)," + @"(?<quad2>\d+)," + @"(?<quad3>\d+)," + @"(?<quad4>\d+)," + @"(?<port1>\d+)," + @"(?<port2>\d+)"); if (!m.Success || m.Groups.Count != 7) { throw new FtpException("Malformed PASV response: " + reply.Message); } // Instruct source server to open a connection to the destination Server if (!(reply = sourceClient.Execute($"PORT {m.Value}")).Success) { throw new FtpCommandException(reply); } return(new FtpFxpSession { SourceServer = sourceClient, TargetServer = destinationClient }); }
/// <summary> /// Opens a FXP PASV connection between the source FTP Server and the destination FTP Server /// </summary> /// <param name="remoteClient">FtpClient instance of the destination FTP Server</param> /// <returns>A data stream ready to be used</returns> private FtpFxpSession OpenPassiveFXPConnection(FtpClient remoteClient, bool trackProgress) { FtpReply reply, reply2; Match m; FtpClient sourceClient = null; FtpClient destinationClient = null; FtpClient progressClient = null; // create a new connection to the source FTP server if EnableThreadSafeDataConnections is set if (EnableThreadSafeDataConnections) { sourceClient = CloneConnection(); sourceClient._AutoDispose = true; sourceClient.CopyStateFlags(this); sourceClient.Connect(); sourceClient.SetWorkingDirectory(GetWorkingDirectory()); } else { sourceClient = this; } // create a new connection to the target FTP server if EnableThreadSafeDataConnections is set if (remoteClient.EnableThreadSafeDataConnections) { destinationClient = remoteClient.CloneConnection(); destinationClient._AutoDispose = true; destinationClient.CopyStateFlags(remoteClient); destinationClient.Connect(); destinationClient.SetWorkingDirectory(remoteClient.GetWorkingDirectory()); } else { destinationClient = remoteClient; } // create a new connection to the target FTP server to track progress // if progress tracking is enabled during this FXP transfer if (trackProgress) { progressClient = remoteClient.CloneConnection(); progressClient._AutoDispose = true; progressClient.CopyStateFlags(remoteClient); progressClient.Connect(); progressClient.SetWorkingDirectory(remoteClient.GetWorkingDirectory()); } sourceClient.SetDataType(sourceClient.FXPDataType); destinationClient.SetDataType(destinationClient.FXPDataType); // send PASV/CPSV commands to destination FTP server to get passive port to be used from source FTP server // first try with PASV - commonly supported by all servers if (!(reply = destinationClient.Execute("PASV")).Success) { // then try with CPSV - known to be supported by glFTPd server // FIXES #666 - glFTPd server - 435 Failed TLS negotiation on data channel if (!(reply2 = destinationClient.Execute("CPSV")).Success) { throw new FtpCommandException(reply); } else { // use the CPSV response and extract the port from it reply = reply2; } } // extract port from response m = Regex.Match(reply.Message, @"(?<quad1>\d+)," + @"(?<quad2>\d+)," + @"(?<quad3>\d+)," + @"(?<quad4>\d+)," + @"(?<port1>\d+)," + @"(?<port2>\d+)"); if (!m.Success || m.Groups.Count != 7) { throw new FtpException("Malformed PASV response: " + reply.Message); } // Instruct source server to open a connection to the destination Server if (!(reply = sourceClient.Execute($"PORT {m.Value}")).Success) { throw new FtpCommandException(reply); } // the FXP session stores the active connections used for this FXP transfer return(new FtpFxpSession { SourceServer = sourceClient, TargetServer = destinationClient, ProgressServer = progressClient, }); }