public async Task <T> ExecuteInDuplexAsync <T>(FtpDataConnectionType connectionType, FtpRequest request) where T : FtpDuplexReponse { var response = Activator.CreateInstance <T>(); response.Request = request; if (!IsConnected) { throw new FtpException("Not Connected"); } var passiveChannel = await OpenPassiveDataStreamAsync(connectionType, request); string bufferResult; while ((bufferResult = await passiveChannel.ReadLineAsync(Encoding)) != null) { if (bufferResult.Length > 0) { response.MessageBody += bufferResult; System.Diagnostics.Debug.WriteLine(bufferResult); } } var finalResponse = await GetReplyAsync <FtpResponse>(); response.Code = finalResponse.Code; response.InfoMessages += finalResponse.Message; return(response); }
public FluentFtpBlobStorage( string hostNameOrAddress, NetworkCredential credentials, FtpDataConnectionType dataConnectionType = FtpDataConnectionType.AutoActive) : this(new FtpClient(hostNameOrAddress, credentials) { DataConnectionType = dataConnectionType }, true) { }
/// <summary> /// Opens a data stream. /// </summary> /// <param name='command'>The command to execute that requires a data stream</param> /// <param name="restart">Restart location in bytes for file transfer</param> /// <returns>The data stream.</returns> FtpDataStream OpenDataStream(string command, long restart) { FtpDataConnectionType type = m_dataConnectionType; FtpDataStream stream = null; #if !CORE14 lock (m_lock) { #endif if (!IsConnected) { Connect(); } // The PORT and PASV commands do not work with IPv6 so // if either one of those types are set change them // to EPSV or EPRT appropriately. if (m_stream.LocalEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) { switch (type) { case FtpDataConnectionType.PORT: type = FtpDataConnectionType.EPRT; FtpTrace.WriteLine(FtpTraceLevel.Info, "Changed data connection type to EPRT because we are connected with IPv6."); break; case FtpDataConnectionType.PASV: case FtpDataConnectionType.PASVEX: type = FtpDataConnectionType.EPSV; FtpTrace.WriteLine(FtpTraceLevel.Info, "Changed data connection type to EPSV because we are connected with IPv6."); break; } } switch (type) { case FtpDataConnectionType.AutoPassive: case FtpDataConnectionType.EPSV: case FtpDataConnectionType.PASV: case FtpDataConnectionType.PASVEX: stream = OpenPassiveDataStream(type, command, restart); break; case FtpDataConnectionType.AutoActive: case FtpDataConnectionType.EPRT: case FtpDataConnectionType.PORT: stream = OpenActiveDataStream(type, command, restart); break; } if (stream == null) { throw new InvalidOperationException("The specified data channel type is not implemented."); } #if !CORE14 } #endif return(stream); }
/// <summary> /// Opens a data stream. /// </summary> /// <param name='request'>The command to execute that requires a data stream</param> /// <returns>The data stream.</returns> public async Task <FtpStreamChannel> OpenDataStreamAsync(FtpRequest request) { FtpStreamChannel stream = null; FtpDataConnectionType type = m_DataConnectionType; // The PORT and PASV commands do not work with IPv6 so // if either one of those types are set change them // to EPSV or EPRT appropriately. if (m_Stream.LocalEndPoint.Type == HostNameType.Ipv6) { switch (type) { case FtpDataConnectionType.PORT: type = FtpDataConnectionType.EPRT; Debug.WriteLine("Changed data connection type to EPRT because we are connected with IPv6."); break; case FtpDataConnectionType.PASV: case FtpDataConnectionType.PASVEX: type = FtpDataConnectionType.EPSV; Debug.WriteLine("Changed data connection type to EPSV because we are connected with IPv6."); break; } } switch (type) { case FtpDataConnectionType.AutoPassive: case FtpDataConnectionType.EPSV: case FtpDataConnectionType.PASV: case FtpDataConnectionType.PASVEX: stream = await m_Stream.OpenPassiveDataStreamAsync(type, request); break; case FtpDataConnectionType.AutoActive: case FtpDataConnectionType.EPRT: case FtpDataConnectionType.PORT: // TODO: break; } if (stream == null) { throw new InvalidOperationException("The specified data channel type is not implemented."); } return(stream); }
public async Task <FtpStreamChannel> OpenPassiveDataStreamAsync(FtpDataConnectionType connectionType, FtpRequest request) { FtpPassiveModeResponse reply; if (connectionType == FtpDataConnectionType.EPSV || connectionType == FtpDataConnectionType.AutoPassive) { if (!(reply = await SetExtendedPassiveMode()).Success) { // if we're connected with IPv4 and data channel type is AutoPassive then fallback to IPv4 if (reply.Type == FtpResponseType.PermanentNegativeCompletion && connectionType == FtpDataConnectionType.AutoPassive && LocalEndPoint.Type == HostNameType.Ipv4) { return(await OpenPassiveDataStreamAsync(FtpDataConnectionType.PASV, request)); } throw new FtpCommandException(reply); } } else { if (LocalEndPoint.Type != HostNameType.Ipv4) { throw new FtpException("Only IPv4 is supported by the PASV command. Use EPSV instead."); } if (!(reply = await SetPassiveMode()).Success) { throw new FtpCommandException(reply); } } var passiveConnection = new FtpStreamChannel(); await passiveConnection.ConnectAsync(reply.HostName, reply.ServiceName); // NOTE: Maybe it is better to just to open the passive channel, and execute the command else where.. if (!(await ExecuteAsync <FtpResponse>(request)).Success) { passiveConnection.Dispose(); throw new FtpCommandException(reply); } return(passiveConnection); }
public static bool Connect(string host, int port = 21, FtpDataConnectionType connectionType = FtpDataConnectionType.PASVEX, string user = "******", string password = "******") { try { if (Client.IsConnected) { Client.Disconnect(); } Client.Host = host; Client.Port = port; Client.DataConnectionType = connectionType; Client.EncryptionMode = FtpEncryptionMode.None; Client.Credentials = new NetworkCredential(user, password); Client.Connect(); return(Client.IsConnected); } catch (Exception ex) { LastError = ex.Message; return(false); } }
public FtpFileSystemOperations(string address, string username, string password, Encoding encoding = null, FtpDataConnectionType connectionType = FtpDataConnectionType.AutoPassive) { if (address == null) { throw new ArgumentNullException(nameof(address)); } address = address.Replace("\\", "/"); if (!address.StartsWith("ftp://", StringComparison.CurrentCultureIgnoreCase)) { address = "ftp://" + address; } var url = new Uri(address); var host = url.Host; var rootDirectory = url.AbsolutePath; var port = url.Port > 0 ? url.Port : 21; if (!string.IsNullOrEmpty(rootDirectory) && rootDirectory != "/") { throw new ArgumentNullException(nameof(address)); } Client = new FtpClient(host, port, new NetworkCredential(username, password)) { Encoding = encoding ?? Encoding.UTF8, DataConnectionType = connectionType, //EncryptionMode = FtpEncryptionMode.Explicit, RetryAttempts = 3 }; Client.ValidateCertificate += (control, args) => args.Accept = true; }
/// <summary> /// Initialize a new instance/ /// </summary> /// <param name="url">Configured url.</param> /// <param name="options">Configured options. cannot be null.</param> public AlternativeFtpBackend(string url, Dictionary <string, string> options) { _accepAllCertificates = CoreUtility.ParseBoolOption(options, OPTION_ACCEPT_ANY_CERTIFICATE); string certHash; options.TryGetValue(OPTION_ACCEPT_SPECIFIED_CERTIFICATE, out certHash); _validHashes = certHash == null ? null : certHash.Split(new[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries); var u = new Utility.Uri(url); u.RequireHost(); if (!string.IsNullOrEmpty(u.Username)) { _userInfo = new System.Net.NetworkCredential(); _userInfo.UserName = u.Username; if (!string.IsNullOrEmpty(u.Password)) { _userInfo.Password = u.Password; } else if (options.ContainsKey("auth-password")) { _userInfo.Password = options["auth-password"]; } } else { if (options.ContainsKey("auth-username")) { _userInfo = new System.Net.NetworkCredential(); _userInfo.UserName = options["auth-username"]; if (options.ContainsKey("auth-password")) { _userInfo.Password = options["auth-password"]; } } } //Bugfix, see http://connect.microsoft.com/VisualStudio/feedback/details/695227/networkcredential-default-constructor-leaves-domain-null-leading-to-null-object-reference-exceptions-in-framework-code if (_userInfo != null) { _userInfo.Domain = ""; } _url = u.SetScheme("ftp").SetQuery(null).SetCredentials(null, null).ToString(); _url = Duplicati.Library.Utility.Utility.AppendDirSeparator(_url, "/"); _listVerify = !CoreUtility.ParseBoolOption(options, "disable-upload-verify"); // Process the aftp-data-connection-type option string dataConnectionTypeString; if (!options.TryGetValue(CONFIG_KEY_AFTP_DATA_CONNECTION_TYPE, out dataConnectionTypeString) || string.IsNullOrWhiteSpace(dataConnectionTypeString)) { dataConnectionTypeString = null; } if (dataConnectionTypeString == null || !Enum.TryParse(dataConnectionTypeString, true, out _dataConnectionType)) { _dataConnectionType = DEFAULT_DATA_CONNECTION_TYPE; } // Process the aftp-encryption-mode option string encryptionModeString; if (!options.TryGetValue(CONFIG_KEY_AFTP_ENCRYPTION_MODE, out encryptionModeString) || string.IsNullOrWhiteSpace(encryptionModeString)) { encryptionModeString = null; } if (encryptionModeString == null || !Enum.TryParse(encryptionModeString, true, out _encryptionMode)) { _encryptionMode = DEFAULT_ENCRYPTION_MODE; } // Process the aftp-ssl-protocols option string sslProtocolsString; if (!options.TryGetValue(CONFIG_KEY_AFTP_SSL_PROTOCOLS, out sslProtocolsString) || string.IsNullOrWhiteSpace(sslProtocolsString)) { sslProtocolsString = null; } if (sslProtocolsString == null || !Enum.TryParse(sslProtocolsString, true, out _sslProtocols)) { _sslProtocols = DEFAULT_SSL_PROTOCOLS; } }
/// <summary> /// Opens the specified type of passive data stream /// </summary> /// <param name="type">Type of passive data stream to open</param> /// <param name="command">The command to execute that requires a data stream</param> /// <param name="restart">Restart location in bytes for file transfer</param> /// <returns>A data stream ready to be used</returns> FtpDataStream OpenPassiveDataStream(FtpDataConnectionType type, string command, long restart) { FtpTrace.WriteFunc("OpenPassiveDataStream", new object[] { type, command, restart }); FtpDataStream stream = null; FtpReply reply; Match m; string host = null; int port = 0; if (m_stream == null) { throw new InvalidOperationException("The control connection stream is null! Generally this means there is no connection to the server. Cannot open a passive data stream."); } if (type == FtpDataConnectionType.EPSV || type == FtpDataConnectionType.AutoPassive) { if (!(reply = Execute("EPSV")).Success) { // if we're connected with IPv4 and data channel type is AutoPassive then fallback to IPv4 if (reply.Type == FtpResponseType.PermanentNegativeCompletion && type == FtpDataConnectionType.AutoPassive && m_stream != null && m_stream.LocalEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { return(OpenPassiveDataStream(FtpDataConnectionType.PASV, command, restart)); } throw new FtpCommandException(reply); } m = Regex.Match(reply.Message, @"\(\|\|\|(?<port>\d+)\|\)"); if (!m.Success) { throw new FtpException("Failed to get the EPSV port from: " + reply.Message); } host = m_host; port = int.Parse(m.Groups["port"].Value); } else { if (m_stream.LocalEndPoint.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) { throw new FtpException("Only IPv4 is supported by the PASV command. Use EPSV instead."); } if (!(reply = 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)); } // PASVEX mode ignores the host supplied in the PASV response if (type == FtpDataConnectionType.PASVEX) { host = m_host; } else { host = (m.Groups["quad1"].Value + "." + m.Groups["quad2"].Value + "." + m.Groups["quad3"].Value + "." + m.Groups["quad4"].Value); } port = (int.Parse(m.Groups["port1"].Value) << 8) + int.Parse(m.Groups["port2"].Value); } stream = new FtpDataStream(this); stream.ConnectTimeout = DataConnectionConnectTimeout; stream.ReadTimeout = DataConnectionReadTimeout; Connect(stream, host, port, InternetProtocolVersions); stream.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.KeepAlive, m_keepAlive); if (restart > 0) { if (!(reply = Execute("REST " + restart)).Success) { throw new FtpCommandException(reply); } } if (!(reply = Execute(command)).Success) { stream.Close(); throw new FtpCommandException(reply); } // the command status is used to determine // if a reply needs to be read from the server // when the stream is closed so always set it // otherwise things can get out of sync. stream.CommandStatus = reply; #if !NO_SSL // this needs to take place after the command is executed if (m_dataConnectionEncryption && m_encryptionmode != FtpEncryptionMode.None) { stream.ActivateEncryption(m_host, this.ClientCertificates.Count > 0 ? this.ClientCertificates : null, m_SslProtocols); } #endif return(stream); }
/// <summary> /// Opens the specified type of active data stream /// </summary> /// <param name="type">Type of passive data stream to open</param> /// <param name="command">The command to execute that requires a data stream</param> /// <param name="restart">Restart location in bytes for file transfer</param> /// <returns>A data stream ready to be used</returns> FtpDataStream OpenActiveDataStream(FtpDataConnectionType type, string command, long restart) { FtpTrace.WriteFunc("OpenActiveDataStream", new object[] { type, command, restart }); FtpDataStream stream = new FtpDataStream(this); FtpReply reply; #if !CORE IAsyncResult ar; #endif if (m_stream == null) { throw new InvalidOperationException("The control connection stream is null! Generally this means there is no connection to the server. Cannot open an active data stream."); } if (m_ActivePorts == null || !m_ActivePorts.Any()) { // Use random port stream.Listen(m_stream.LocalEndPoint.Address, 0); } else { var success = false; // Use one of the specified ports foreach (var port in m_ActivePorts) { try { stream.Listen(m_stream.LocalEndPoint.Address, port); success = true; } catch (SocketException se) { #if NETFX // Already in use if (se.ErrorCode != 10048) { throw; } #else throw; #endif } } // No usable port found if (!success) { throw new Exception("No valid active data port available!"); } } #if !CORE ar = stream.BeginAccept(null, null); #endif if (type == FtpDataConnectionType.EPRT || type == FtpDataConnectionType.AutoActive) { int ipver = 0; switch (stream.LocalEndPoint.AddressFamily) { case System.Net.Sockets.AddressFamily.InterNetwork: ipver = 1; // IPv4 break; case System.Net.Sockets.AddressFamily.InterNetworkV6: ipver = 2; // IPv6 break; default: throw new InvalidOperationException("The IP protocol being used is not supported."); } if (!(reply = Execute("EPRT |" + ipver + "|" + GetLocalAddress(stream.LocalEndPoint.Address) + "|" + stream.LocalEndPoint.Port + "|")).Success) { // if we're connected with IPv4 and the data channel type is AutoActive then try to fall back to the PORT command if (reply.Type == FtpResponseType.PermanentNegativeCompletion && type == FtpDataConnectionType.AutoActive && m_stream != null && m_stream.LocalEndPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { stream.ControlConnection = null; // we don't want this failed EPRT attempt to close our control connection when the stream is closed so clear out the reference. stream.Close(); return(OpenActiveDataStream(FtpDataConnectionType.PORT, command, restart)); } else { stream.Close(); throw new FtpCommandException(reply); } } } else { if (m_stream.LocalEndPoint.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) { throw new FtpException("Only IPv4 is supported by the PORT command. Use EPRT instead."); } if (!(reply = Execute("PORT " + GetLocalAddress(stream.LocalEndPoint.Address).Replace('.', ',') + "," + stream.LocalEndPoint.Port / 256 + "," + stream.LocalEndPoint.Port % 256)).Success) { stream.Close(); throw new FtpCommandException(reply); } } if (restart > 0) { if (!(reply = Execute("REST " + restart)).Success) { throw new FtpCommandException(reply); } } if (!(reply = Execute(command)).Success) { stream.Close(); throw new FtpCommandException(reply); } // the command status is used to determine // if a reply needs to be read from the server // when the stream is closed so always set it // otherwise things can get out of sync. stream.CommandStatus = reply; #if CORE stream.AcceptAsync().Wait(); #else ar.AsyncWaitHandle.WaitOne(m_dataConnectionConnectTimeout); if (!ar.IsCompleted) { stream.Close(); throw new TimeoutException("Timed out waiting for the server to connect to the active data socket."); } stream.EndAccept(ar); #endif #if !NO_SSL if (m_dataConnectionEncryption && m_encryptionmode != FtpEncryptionMode.None) { stream.ActivateEncryption(m_host, this.ClientCertificates.Count > 0 ? this.ClientCertificates : null, m_SslProtocols); } #endif stream.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, System.Net.Sockets.SocketOptionName.KeepAlive, m_keepAlive); stream.ReadTimeout = m_dataConnectionReadTimeout; return(stream); }
/// <summary> /// Constructs an instance of FTP client from host name and credentials /// </summary> public static IBlobStorage Ftp(this IBlobStorageFactory factory, string hostNameOrAddress, NetworkCredential credentials, FtpDataConnectionType dataConnectionType = FtpDataConnectionType.AutoActive) { return(new FluentFtpBlobStorage(hostNameOrAddress, credentials, dataConnectionType)); }
/// <summary> /// Initialize a new instance/ /// </summary> /// <param name="url">Configured url.</param> /// <param name="options">Configured options. cannot be null.</param> public AlternativeFtpBackend(string url, Dictionary<string, string> options) { _accepAllCertificates = CoreUtility.ParseBoolOption(options, OPTION_ACCEPT_ANY_CERTIFICATE); string certHash; options.TryGetValue(OPTION_ACCEPT_SPECIFIED_CERTIFICATE, out certHash); _validHashes = certHash == null ? null : certHash.Split(new[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries); var u = new Utility.Uri(url); u.RequireHost(); if (!string.IsNullOrEmpty(u.Username)) { _userInfo = new System.Net.NetworkCredential(); _userInfo.UserName = u.Username; if (!string.IsNullOrEmpty(u.Password)) _userInfo.Password = u.Password; else if (options.ContainsKey("auth-password")) _userInfo.Password = options["auth-password"]; } else { if (options.ContainsKey("auth-username")) { _userInfo = new System.Net.NetworkCredential(); _userInfo.UserName = options["auth-username"]; if (options.ContainsKey("auth-password")) _userInfo.Password = options["auth-password"]; } } //Bugfix, see http://connect.microsoft.com/VisualStudio/feedback/details/695227/networkcredential-default-constructor-leaves-domain-null-leading-to-null-object-reference-exceptions-in-framework-code if (_userInfo != null) _userInfo.Domain = ""; _url = u.SetScheme("ftp").SetQuery(null).SetCredentials(null, null).ToString(); if (!_url.EndsWith("/")) { _url += "/"; } _listVerify = !CoreUtility.ParseBoolOption(options, "disable-upload-verify"); // Process the aftp-data-connection-type option string dataConnectionTypeString; if (!options.TryGetValue(CONFIG_KEY_AFTP_DATA_CONNECTION_TYPE, out dataConnectionTypeString) || string.IsNullOrWhiteSpace(dataConnectionTypeString)) { dataConnectionTypeString = null; } if (dataConnectionTypeString == null || !Enum.TryParse(dataConnectionTypeString, true, out _dataConnectionType)) { _dataConnectionType = DEFAULT_DATA_CONNECTION_TYPE; } // Process the aftp-encryption-mode option string encryptionModeString; if (!options.TryGetValue(CONFIG_KEY_AFTP_ENCRYPTION_MODE, out encryptionModeString) || string.IsNullOrWhiteSpace(encryptionModeString)) { encryptionModeString = null; } if (encryptionModeString == null || !Enum.TryParse(encryptionModeString, true, out _encryptionMode)) { _encryptionMode = DEFAULT_ENCRYPTION_MODE; } // Process the aftp-ssl-protocols option string sslProtocolsString; if (!options.TryGetValue(CONFIG_KEY_AFTP_SSL_PROTOCOLS, out sslProtocolsString) || string.IsNullOrWhiteSpace(sslProtocolsString)) { sslProtocolsString = null; } if (sslProtocolsString == null || !Enum.TryParse(sslProtocolsString, true, out _sslProtocols)) { _sslProtocols = DEFAULT_SSL_PROTOCOLS; } }
/// <summary> /// Creates a Ftp file system. /// </summary> /// <param name="address">The ftp host address.</param> /// <param name="username">The user name.</param> /// <param name="password">The password.</param> /// <param name="encoding">The encoding applied to the contents of files.</param> /// <param name="connectionType">The Ftp Data connection type.</param> /// <returns>A Ftp file system contains the procedures that are used to perform file and directory operations.</returns> public static FileSystem Create(string address, string username, string password, Encoding encoding = null, FtpDataConnectionType connectionType = FtpDataConnectionType.AutoPassive) { return(new FileSystem(new FtpFileSystemOperations(address, username, password, encoding, connectionType))); }