0

I'm attempting to download files from an FTPS server using the functionality provided by System.Net (.Net Framework 4.8). I'm using the following code:

var serverUri = new System.Uri("ftp://my.ftp.server.com/directory/");
var request = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(serverUri);
request.Method = System.Net.WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new System.Net.NetworkCredential("username", "password");
request.KeepAlive = true;
request.UseBinary = true;
request.EnableSsl = true;
request.UsePassive = true;

System.Net.ServicePoint sp = request.ServicePoint;
sp.ConnectionLimit = 1;
var response = (System.Net.FtpWebResponse)request.GetResponse();
System.IO.StreamReader readStream = null;

try
{
    using (Stream responseStream = response.GetResponseStream())
    {
        readStream = new System.IO.StreamReader(responseStream, System.Text.Encoding.UTF8);

        if (readStream != null)
        {
            string directoryListing = readStream.ReadToEnd(); // <-- Fails here!
            // Process directory listing...
        }

        readStream.Close();
    }
}
catch (Exception ex)
{
    Console.WriteLine($"### ERROR ### {ex.Message}");
    Console.WriteLine($"### ERROR ### [{response.StatusCode}] {response.StatusDescription}");
}
finally
{
    if (readStream != null)
        readStream.Close();

    if (response != null)
        response.Close();
}

Unfortunately the code fails most of the time at the line: string directoryListing = readStream.ReadToEnd();. Most of the time means, around one out of between 5-20 (sometimes more) consecutive attempts (roughly every second) succeeds delivering the desired result. Thus far I haven't been able to find any rule (timeout, etc.) for when it succeeds. The output of the catch block is:

### ERROR ### The remote server returned an error: (425) Can't open data connection.
### ERROR ### [CantOpenData] 425 Unable to build data connection: TLS session of data connection not resumed.

Setting EnableSsl = false results in the error: (503) Bad sequence of commands.

Setting UsePassive = false results in failing to establish a connection (timeout occurs).

Setting KeepAlive = false or UseBinary = false doesn't change anything.

What does work is setting the TLS version the client uses to 1.2:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

...just before the line response = (FtpWebResponse)request.GetResponse();. According to (https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp-#tls-protocol-version-support) TLS 1.3 should be functional on Windows 11 (which I'm using).

The server I'm trying to communicate with:

FileZilla Pro Enterprise Server 1.6.3 
Please visit https://filezilla-project.org/

The error message above indicates that I should be storing session data and reusing it, yet I haven't found any information on how I can access session data through the functionality provided within System.Net.

So my question: is the implemention of .Net's communication layer using TLS 1.3 faulty/incomplete or am I doing something wrong? In the latter case, how can I fix my code to use TLS 1.3 (wihtout using 3rd party components)? Any help greatly appreciated!

Krys
  • 39
  • 9

0 Answers0