Recommended way to build for gnutls support?
There seems to be most of whats needed already there, but with no docs on how to use it I am unsure what is needed.
- Unsafe flag checked
- defined
USE_GNU_SSL_STREAM
Yet GnuSslStream remains undefined? I am not sure what is the suggested path to take to enable this?
You also have to reference the GnuSslStream shared project from the main FubarDev.FtpServer project. This is a bug that you'd be able to fix easily.
Ok so I have referenced it in the main project
<Import Project="../../third-party/GnuSslStream/GnuSslStream.projitems" Label="Shared" />
But now when I test I receive the following exception...
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Net.Security.ReflectUtil.GetField(Object obj, String fieldName) in FtpServer\third-party\GnuSslStream\ReflectUtil.cs:line 14
at System.Net.Security.SslDirectCall.GetHandlesForNetCore30(SslStream sslStream) in FtpServer\third-party\GnuSslStream\SslDirectCall.cs:line 174
at System.Net.Security.SslDirectCall.<>c__DisplayClass1_0.<GetNativeApiHelpers>b__4() in FtpServer\third-party\GnuSslStream\SslDirectCall.cs:line 116
at System.Net.Security.SslDirectCall.CloseNotify(SslStream sslStream) in FtpServer\third-party\GnuSslStream\SslDirectCall.cs:line 24
at System.Net.Security.GnuSslStream.Close() in FtpServer\third-party\GnuSslStream\GnuSslStream.cs:line 96
at FubarDev.FtpServer.Authentication.DefaultSslStreamWrapperFactory.CloseStreamAsync(Stream sslStream, CancellationToken cancellationToken) in FtpServer\src\FubarDev.FtpServer\Authentication\DefaultSslStreamWrapperFactory.cs:line 89
at FubarDev.FtpServer.ConnectionHandlers.SslStreamConnectionAdapter.StopAsync(CancellationToken cancellationToken) in FtpServer\src\FubarDev.FtpServer\ConnectionHandlers\SslStreamConnectionAdapter.cs:line 112
at FubarDev.FtpServer.ServerCommandHandlers.CloseConnectionServerCommandHandler.ExecuteAsync(CloseConnectionServerCommand command, CancellationToken cancellationToken) in FtpServer\src\FubarDev.FtpServer\ServerCommandHandlers\CloseConnectionServerCommandHandler.cs:line 36
at FubarDev.FtpServer.FtpConnection.SendResponsesAsync(ChannelReader`1 serverCommandReader, CancellationToken cancellationToken) in FtpServer\src\FubarDev.FtpServer\FtpConnection.cs:line 623
Testing with openssl s_client
echo quit | openssl s_client -connect 127.0.0.1:21 -starttls ftp
Am I missing some vital detail here? Does this fix only work on a specific .net version?
I wiped my local folder and did a fresh pull. The error I received this time is
System.InvalidOperationException: Sequence contains more than one element
at System.Linq.ThrowHelper.ThrowMoreThanOneElementException()
at System.Linq.Enumerable.TryGetSingle[TSource](IEnumerable1 source, Boolean& found)
at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source)
at System.Net.Security.ReflectUtil.GetField(Object obj, String fieldName) in \FtpServer\third-party\GnuSslStream\ReflectUtil.cs:line 15
at System.Net.Security.SslDirectCall.<>c__DisplayClass1_0.<GetNativeApiHelpers>b__5() in \FtpServer\third-party\GnuSslStream\SslDirectCall.cs:line 117
at System.Net.Security.SslDirectCall.CloseNotify(SslStream sslStream) in \FtpServer\third-party\GnuSslStream\SslDirectCall.cs:line 87
at System.Net.Security.GnuSslStream.Close() in \FtpServer\third-party\GnuSslStream\GnuSslStream.cs:line 96
at System.IO.Stream.Dispose()
at FubarDev.FtpServer.Authentication.DefaultSslStreamWrapperFactory.CloseStreamAsync(Stream sslStream, CancellationToken cancellationToken) in \FtpServer\src\FubarDev.FtpServer\Authentication\DefaultSslStreamWrapperFactory.cs:line 89
at FubarDev.FtpServer.ConnectionHandlers.SslStreamConnectionAdapter.StopAsync(CancellationToken cancellationToken) in \FtpServer\src\FubarDev.FtpServer\ConnectionHandlers\SslStreamConnectionAdapter.cs:line 112
at FubarDev.FtpServer.FtpConnection.StopAsync() in \FtpServer\src\FubarDev.FtpServer\FtpConnection.cs:line 412
I modified GetValue in ReflectionUtil. To inspect.
public static object GetField(object obj, string fieldName)
{
var tp = obj.GetType();
var fields = GetAllFields(tp).Where(f => f.Name == fieldName).ToList();
if (fields.Count > 1)
{
Console.WriteLine($"Multiple fields found with name {fieldName}.");
}
foreach (var f in fields)
{
Console.WriteLine($"Field found: {f.Name}, DeclaringType: {f.DeclaringType}");
}
var field = fields.FirstOrDefault(f => f.DeclaringType == tp) ?? fields.FirstOrDefault();
return field?.GetValue(obj);
}
Multiple fields found with name _innerStream.
Field found: _innerStream, DeclaringType: System.Net.Security.SslStream
Field found: _innerStream, DeclaringType: System.Net.Security.AuthenticatedStream
Perhaps GetField() should be modified?
public static object GetField(object obj, string fieldName)
{
var tp = obj.GetType();
var fields = GetAllFields(tp).Where(f => f.Name == fieldName);
var field = fields.FirstOrDefault(f => f.DeclaringType == tp) ?? fields.FirstOrDefault();
return field?.GetValue(obj);
}
FileZilla client connects with explicit tls and works fine now. I just dont understand why I have multiple _innerStream?
I remember that there was a change in the source files. However, I thought that this GNU TLS workaround wouldn't be necessary anymore due to the changes in .NET (Core) sometime before 5.0.
I have modified DefaultSslStreamWrapperFactory.CloseStreamASync() to the following
public Task CloseStreamAsync(Stream sslStream, CancellationToken cancellationToken)
{
if (sslStream is SslStream s)
{
#if NET461 || NETSTANDARD2_0
s.Close();
#elif NETSTANDARD2_1
s.ShutdownAsync().Wait();
#else
s.Dispose();
#endif
}
return Task.CompletedTask;
}
I can now build and run without GnuSslStream and filezilla works well (and openssl s_client does not complain upon conn close either)
I am not well enough experienced with net standard to understand why you arent doing this already? Or perhaps just an oversight? I got the idea from a thread you started, actually