Can connect to FTP using FileZilla or WinSCP, but not with FtpWebRequest or FluentFTP
c#, fluentftp, ftp, ftpwebrequest, ssl
Solution
.NET framework does not support TLS/SSL session reuse. If your server requires it (what it looks it does and what is quite common nowadays and what is good thing for security), you cannot use `FtpWebRequest` nor FluentFTP. Both use the .NET implementation of TLS/SSL.
You will have to use FTP library that uses own TLS/SSL implementation.
You can use my WinSCP .NET assembly. Though contrary to FluentFTP, it's not a native .NET library, it has dependencies on an external binary. But that's what makes it working.
Some references:
- https://github.com/robinrodricks/FluentFTP/issues/347
- https://github.com/dotnet/runtime/issues/27916
- "Authentication failed because the remote party has closed the transport stream" when transferring to/from FTP server over TLS/SSL using FluentFTP
- Upload file to implicit FTPS server in C# with TLS session reuse
- Suddenly getting "150 Opening Data channel for file download from server" after the FTP downloads was working for years – According to this post and other references elsewhere, the TLS/SSL session reuse was supported earlier with .NET Framework, but some update broke it. In .NET Core it was never working (see also the `dotnet` GitHub link above).
Problem
I am trying to open an FTP connection over SSL in my code. I'm able to connect and list a directory using FileZilla of WinSCP. But when listing the directory through .NET code using `FtpWebClient`, I get the error (425) Can't open data connection Since I'm able to connect using FileZilla from the same computer, I'm not sure how to go about troubleshooting this. Here's my code ``` public void FtpStuff() { string url = "ftp://my.server.com"; FtpWebRequest request = (FtpWebRequest)WebRequest.Create(url); request.Credentials = new NetworkCredential("myname", "password"); request.EnableSsl = true; request.Method = WebRequestMethods.Ftp.ListDirectory; FtpWebResponse response = (FtpWebResponse)request.GetResponse(); StreamReader streamReader = new StreamReader(response.GetResponseStream()); // This is the line that throws the exception string line = streamReader.ReadLine(); } ``` I also tried FluentFTP. Here's my code for that. I get the exception Unable to build data connection: Operation not permitted. ``` public void FtpStuff() { FtpClient client = new FtpClient(); client.Host = "my.server.com"; client.Credentials = new NetworkCredential("myname", "password"); client.EncryptionMode = FtpEncryptionMode.Explicit; client.Connect(); // This line gives me an exception. var files = client.GetListing(); } ``` Here is the logging information from FluentFTP. I changed the real user name and IP, but the rest of the data (including the port) is the real data. My FTP service provider specifies that I have to connect on port 21. The problem seems to happen towards the end after the `EPSV` command is issued and a connection on a new port is established. ``` # Connect() The thread 0x5514 has exited with code 0 (0x0). The thread 0xc80 has exited with code 0 (0x0). The thread 0x89d4 has exited with code 0 (0x0). Status: Connecting to 123.123.123.123:21 Response: 220 FTP Server Ready Command: AUTH TLS Response: 234 AUTH TLS successful Status: FTPS Authentication Successful Status: Time to activate encryption: 0h 0m 0s. Total Seconds: 0.1339995. Command: USER me@mysite.com The thread 0x6ddc has exited with code 0 (0x0). Response: 331 Password required for me@mysite.com Status: Testing connectivity using Socket.Poll()... Command: PASS *** Response: 230-*************************************************************************** Response: NOTICE TO USERS Response: This computer system is private property. It is for authorized use only. Response: Users (authorized or unauthorized) have no explicit or implicit Response: expectation of privacy. Response: Response: Any or all uses of this system and all files on this system may be Response: intercepted, monitored, recorded, copied, audited and inspected by Response: using this system, the user consents to such interception, monitoring, Response: recording, copying, auditing, inspection, and disclosure at the Response: discretion of such personnel or officials. Unauthorized or improper use Response: of this system may result in civil and criminal penalties and Response: administrative or disciplinary action, as appropriate. By continuing to Response: use this system you indicate your awareness of and consent to these terms Response: and conditions of use. LOG OFF IMMEDIATELY if you do not agree to the Response: conditions stated in this warning. Response: **************************************************************************** Response: 230 User me@mysite.com logged in Command: PBSZ 0 Response: 200 PBSZ 0 successful Command: PROT P Response: 200 Protection set to Private Command: FEAT Response: 211-Features: Response: AUTH TLS Response: CCC Response: CLNT Response: EPRT Response: EPSV Response: HOST Response: MDTM Response: MFF modify;UNIX.group;UNIX.mode; Response: MFMT Response: MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.groupname*;UNIX.mode*;UNIX.owner*;UNIX.ownername*; Response: PBSZ Response: PROT Response: REST STREAM Response: SIZE Response: SSCN Response: TVFS Response: 211 End Status: Text encoding: System.Text.ASCIIEncoding Command: SYST Response: 215 UNIX Type: L8 # GetListing(null, Auto) # GetWorkingDirectory() Command: PWD Response: 257 "/" is the current directory Command: TYPE I Response: 200 Type set to I # OpenPassiveDataStream(AutoPassive, "MLSD /", 0) Command: EPSV Response: 229 Entering Extended Passive Mode (|||50304|) Status: Connecting to 123.123.123.123:50304 Command: MLSD / Response: 150 Opening BINARY mode data connection for MLSD Status: FTPS Authentication Successful Status: Time to activate encryption: 0h 0m 0s. Total Seconds: 0.1210002. +---------------------------------------+ ----------------------------------------- Status: Disposing FtpSocketStream... # CloseDataStream() Response: 425 Unable to build data connection: Operation not permitted Status: Disposing FtpSocketStream... Exception thrown: 'FluentFTP.FtpCommandException' in FluentFTP.dll ``` Here are my FileZilla logs. ``` Status: Resolving address of mysite.com Status: Connecting to 123.123.123.123:21... Status: Connection established, waiting for welcome message... Response: 220 FTP Server Ready Command: AUTH TLS Response: 234 AUTH TLS successful Status: Initializing TLS... Status: Verifying certificate... Status: TLS connection established. Command: USER me@mysite.com Response: 331 Password required for me@mysite.com Command: PASS ************ Response: 230-*************************************************************************** Response: NOTICE TO USERS Response: This computer system is private property. It is for authorized use only. Response: Users (authorized or unauthorized) have no explicit or implicit Response: expectation of privacy. Response: Response: Any or all uses of this system and all files on this system may be Response: intercepted, monitored, recorded, copied, audited and inspected by Response: using this system, the user consents to such interception, monitoring, Response: recording, copying, auditing, inspection, and disclosure at the Response: discretion of such personnel or officials. Unauthorized or improper use Response: of this system may result in civil and criminal penalties and Response: administrative or disciplinary action, as appropriate. By continuing to Response: use this system you indicate your awareness of and consent to these terms Response: and conditions of use. LOG OFF IMMEDIATELY if you do not agree to the Response: conditions stated in this warning. Response: **************************************************************************** Response: 230 User me@mysite.com logged in Command: SYST Response: 215 UNIX Type: L8 Command: FEAT Response: 211-Features: Response: AUTH TLS Response: CCC Response: CLNT Response: EPRT Response: EPSV Response: HOST Response: MDTM Response: MFF modify;UNIX.group;UNIX.mode; Response: MFMT Response: MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.groupname*;UNIX.mode*;UNIX.owner*;UNIX.ownername*; Response: PBSZ Response: PROT Response: REST STREAM Response: SIZE Response: SSCN Response: TVFS Response: 211 End Status: Server does not support non-ASCII characters. Command: PBSZ 0 Response: 200 PBSZ 0 successful Command: PROT P Response: 200 Protection set to Private Status: Logged in Status: Retrieving directory listing... Command: PWD Response: 257 "/" is the current directory Command: TYPE I Response: 200 Type set to I Command: PASV Response: 227 Entering Passive Mode (123,123,123,123,197,68). Command: MLSD Response: 150 Opening BINARY mode data connection for MLSD Response: 226 Transfer complete Status: Directory listing of "/" successful ``` I can also connect using WinSCP. As suggested in comments, I did check if TLS/SSL session ID is reused when opening the data connection. It seems that it is. ``` 227 Entering Passive Mode (???) MLSD Connecting to ??? ... Connection pending Data connection opened Trying reuse main TLS session ID Session ID reused 150 Opening data channel for directory listing of "/" ```