From 01fbd0b74ec7580089d986e2aae97057ff9b0a8d Mon Sep 17 00:00:00 2001 From: Eveldee Date: Sat, 20 Jul 2019 14:31:33 +0200 Subject: [PATCH] Add ForceDataPort configuration Use StaticDataConnection --- DearFTP/Configurations/Configuration.cs | 2 +- DearFTP/Configurations/ServerConfiguration.cs | 1 + .../Connection/Commands/ProtectionCommand.cs | 4 +- ...Connection.cs => DynamicDataConnection.cs} | 37 +++--- DearFTP/Connection/IDataConnection.cs | 21 ++++ DearFTP/Connection/Session.cs | 5 +- DearFTP/Connection/StaticDataConnection.cs | 108 ++++++++++++++++++ DearFTP/FtpServer.cs | 1 + 8 files changed, 156 insertions(+), 23 deletions(-) rename DearFTP/Connection/{DataConnection.cs => DynamicDataConnection.cs} (66%) create mode 100644 DearFTP/Connection/IDataConnection.cs create mode 100644 DearFTP/Connection/StaticDataConnection.cs diff --git a/DearFTP/Configurations/Configuration.cs b/DearFTP/Configurations/Configuration.cs index 8d84d7b..c56c647 100644 --- a/DearFTP/Configurations/Configuration.cs +++ b/DearFTP/Configurations/Configuration.cs @@ -108,7 +108,7 @@ namespace DearFTP.Configurations public void Save() { - var serializer = new SerializerBuilder().EmitDefaults().Build(); + var serializer = new SerializerBuilder().Build(); File.WriteAllText(ConfigurationPath, serializer.Serialize(this)); } diff --git a/DearFTP/Configurations/ServerConfiguration.cs b/DearFTP/Configurations/ServerConfiguration.cs index 7914c8b..ea9d758 100644 --- a/DearFTP/Configurations/ServerConfiguration.cs +++ b/DearFTP/Configurations/ServerConfiguration.cs @@ -7,6 +7,7 @@ namespace DearFTP.Configurations class ServerConfiguration { public ushort Port { get; set; } = 21; + public ushort ForceDataPort { get; set; } = 0; public string MOTD { get; set; } = "DearFTP v0.1"; public string LoginMessage { get; set; } = "Logged in as %user%"; diff --git a/DearFTP/Connection/Commands/ProtectionCommand.cs b/DearFTP/Connection/Commands/ProtectionCommand.cs index 6cddd44..b7b3bd5 100644 --- a/DearFTP/Connection/Commands/ProtectionCommand.cs +++ b/DearFTP/Connection/Commands/ProtectionCommand.cs @@ -16,11 +16,11 @@ namespace DearFTP.Connection.Commands switch (argument.ToUpper()) { case "C": - session.DataConnection.DesactivateTsl(); + session.DataConnection.DesactivateTls(); stream.Send(ResponseCode.OK, "Data protection cleared."); break; case "P": - session.DataConnection.ActivateTsl(); + session.DataConnection.ActivateTls(); stream.Send(ResponseCode.OK, "Data protection set."); break; default: diff --git a/DearFTP/Connection/DataConnection.cs b/DearFTP/Connection/DynamicDataConnection.cs similarity index 66% rename from DearFTP/Connection/DataConnection.cs rename to DearFTP/Connection/DynamicDataConnection.cs index ab96873..328f4b3 100644 --- a/DearFTP/Connection/DataConnection.cs +++ b/DearFTP/Connection/DynamicDataConnection.cs @@ -11,15 +11,14 @@ using System.Threading.Tasks; namespace DearFTP.Connection { - class DataConnection + class DynamicDataConnection : IDataConnection { - public const int Timeout = 100_000; + public const int Timeout = 10_000; - public TcpListener Listener { get; private set; } - public TcpClient Client { get; private set; } public Stream Stream { get; private set; } public bool IsTslProtected { get; private set; } - public int Port => ((IPEndPoint)Listener.LocalEndpoint).Port; + + public int Port => ((IPEndPoint)_listener.LocalEndpoint).Port; public bool IsAvailable { get @@ -41,9 +40,11 @@ namespace DearFTP.Connection } } + private TcpListener _listener; + private TcpClient _client; private Task _acceptTask; - public DataConnection() + public DynamicDataConnection() { IsTslProtected = false; } @@ -51,41 +52,41 @@ namespace DearFTP.Connection public void Create() { // Clean old connections - if (Client?.Connected == true) + if (_client?.Connected == true) { Close(); } - Listener = new TcpListener(IPAddress.Any, 0); - Listener.Start(); + _listener = new TcpListener(IPAddress.Any, 0); + _listener.Start(); } - public void AcceptClient(bool authenticateAfter = false) + public void AcceptClient() { - _acceptTask = Listener.AcceptTcpClientAsync().ContinueWith(t => + _acceptTask = _listener.AcceptTcpClientAsync().ContinueWith(t => { - Client = t.Result; + _client = t.Result; if (IsTslProtected) { - var sslStream = new SslStream(Client.GetStream(), false); + var sslStream = new SslStream(_client.GetStream(), false); sslStream.AuthenticateAsServer(FtpServer.Instance.Configuration.Tls.X509Certificate, false, true); Stream = sslStream; } else { - Stream = Client.GetStream(); + Stream = _client.GetStream(); } }); } - public void ActivateTsl() + public void ActivateTls() { IsTslProtected = true; } - public void DesactivateTsl() + public void DesactivateTls() { IsTslProtected = false; } @@ -93,8 +94,8 @@ namespace DearFTP.Connection public void Close() { Stream.Close(); - Client.Close(); - Listener.Stop(); + _client.Close(); + _listener.Stop(); } } } diff --git a/DearFTP/Connection/IDataConnection.cs b/DearFTP/Connection/IDataConnection.cs new file mode 100644 index 0000000..6a07a54 --- /dev/null +++ b/DearFTP/Connection/IDataConnection.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace DearFTP.Connection +{ + interface IDataConnection + { + Stream Stream { get; } + int Port { get; } + bool IsTslProtected { get; } + bool IsAvailable { get; } + + void Create(); + void AcceptClient(); + void ActivateTls(); + void DesactivateTls(); + void Close(); + } +} diff --git a/DearFTP/Connection/Session.cs b/DearFTP/Connection/Session.cs index 88c9435..099a9a9 100644 --- a/DearFTP/Connection/Session.cs +++ b/DearFTP/Connection/Session.cs @@ -22,7 +22,7 @@ namespace DearFTP.Connection public Share[] WritablesShares { get; set; } public NavigablePath NavigablePath { get; set; } public FtpStream FtpStream { get; private set; } - public DataConnection DataConnection { get; set; } + public IDataConnection DataConnection { get; set; } public int RestartPosition { get; set; } public bool IsTlsProtected { get; private set; } public string CurrentWorkingDirectory => NavigablePath.CurrentDirectory; @@ -43,7 +43,7 @@ namespace DearFTP.Connection Configuration = FtpServer.Instance.Configuration; CommandsDispatcher = FtpServer.Instance.CommandsDispatcher; Logger = FtpServer.Instance.Logger; - DataConnection = new DataConnection(); + DataConnection = Configuration.Server.ForceDataPort == 0 ? (IDataConnection)new DynamicDataConnection() : new StaticDataConnection(); RestartPosition = 0; IsTlsProtected = false; } @@ -94,6 +94,7 @@ namespace DearFTP.Connection _sslStream?.Close(); _networkStream.Close(); _client.Close(); + DataConnection.Close(); } } } diff --git a/DearFTP/Connection/StaticDataConnection.cs b/DearFTP/Connection/StaticDataConnection.cs new file mode 100644 index 0000000..13b79fd --- /dev/null +++ b/DearFTP/Connection/StaticDataConnection.cs @@ -0,0 +1,108 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Threading.Tasks; + +namespace DearFTP.Connection +{ + class StaticDataConnection : IDataConnection + { + public const int Timeout = 10_000; + + public Stream Stream { get; private set; } + public bool IsTslProtected { get; private set; } + + public int Port => ((IPEndPoint)_listener.LocalEndpoint).Port; + public bool IsAvailable + { + get + { + if (_acceptTask == null) + { + return false; + } + else if (_acceptTask.Wait(Timeout)) + { + return true; + } + else + { + _acceptTask.Dispose(); + _acceptTask = null; + return false; + } + } + } + + private static TcpListener _listener; + private static Task _acceptTask; + private TcpClient _client; + + public StaticDataConnection() + { + if (_listener == null) + { + _listener = new TcpListener(IPAddress.Any, FtpServer.Instance.Configuration.Server.ForceDataPort); + _listener.Start(); + } + + IsTslProtected = false; + } + + public void AcceptClient() + { + if (_acceptTask?.IsCompleted == false) + { + _acceptTask.Wait(Timeout); + + _acceptTask.Dispose(); + _acceptTask = null; + } + + _acceptTask = _listener.AcceptTcpClientAsync().ContinueWith(t => + { + _client = t.Result; + + if (IsTslProtected) + { + var sslStream = new SslStream(_client.GetStream(), false); + sslStream.AuthenticateAsServer(FtpServer.Instance.Configuration.Tls.X509Certificate, false, true); + + Stream = sslStream; + } + else + { + Stream = _client.GetStream(); + } + }); + } + + public void ActivateTls() + { + IsTslProtected = true; + } + + public void Close() + { + Stream.Close(); + _client.Close(); + } + + public void Create() + { + // Nothing to create as the TcpListener is shared by all + } + + public void DesactivateTls() + { + IsTslProtected = false; + } + + public static void Stop() + { + _listener?.Stop(); + } + } +} diff --git a/DearFTP/FtpServer.cs b/DearFTP/FtpServer.cs index af976d6..9c40b31 100644 --- a/DearFTP/FtpServer.cs +++ b/DearFTP/FtpServer.cs @@ -46,6 +46,7 @@ namespace DearFTP { _isRunning = false; _listener.Stop(); + StaticDataConnection.Stop(); } private void TcpLoop()