Add SSL/TLS protocol support
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
using System;
|
using DearFTP.Utils;
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Security.Cryptography;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
namespace DearFTP.Configurations
|
namespace DearFTP.Configurations
|
||||||
@@ -31,6 +32,7 @@ namespace DearFTP.Configurations
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ServerConfiguration Server { get; set; } = new ServerConfiguration();
|
public ServerConfiguration Server { get; set; } = new ServerConfiguration();
|
||||||
|
public TlsConfiguration Tls { get; set; } = new TlsConfiguration();
|
||||||
public Share[] Shares { get; set; } = Array.Empty<Share>();
|
public Share[] Shares { get; set; } = Array.Empty<Share>();
|
||||||
public User[] Users { get; set; } = Array.Empty<User>();
|
public User[] Users { get; set; } = Array.Empty<User>();
|
||||||
|
|
||||||
@@ -58,6 +60,49 @@ namespace DearFTP.Configurations
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Tls.ForceTls && !Tls.AllowTls)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Tls is forced but not allowed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tls.AllowTls)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Tls.CertificatePath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Tls is activated, but no certificate is specified.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var certificate = new X509Certificate2(Tls.CertificatePath);
|
||||||
|
|
||||||
|
if (!certificate.HasPrivateKey)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Tls.PrivateKeyPath))
|
||||||
|
{
|
||||||
|
Console.WriteLine("No private key loaded and no path is specified.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var privateKeyBytes = OpenSslKey.DecodePkcs8PrivateKey(File.ReadAllText(Tls.PrivateKeyPath));
|
||||||
|
var privateKey = OpenSslKey.DecodePrivateKeyInfo(privateKeyBytes);
|
||||||
|
|
||||||
|
certificate = certificate.CopyWithPrivateKey(privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tls.X509Certificate = certificate;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Can't load certificate: {e.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
DearFTP/Configurations/TlsConfiguration.cs
Normal file
19
DearFTP/Configurations/TlsConfiguration.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
|
namespace DearFTP.Configurations
|
||||||
|
{
|
||||||
|
class TlsConfiguration
|
||||||
|
{
|
||||||
|
public bool AllowTls { get; set; } = false;
|
||||||
|
public bool ForceTls { get; set; } = false;
|
||||||
|
public string CertificatePath { get; set; } = "";
|
||||||
|
public string PrivateKeyPath { get; set; } = "";
|
||||||
|
|
||||||
|
[YamlIgnore()]
|
||||||
|
public X509Certificate2 X509Certificate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
40
DearFTP/Connection/Commands/AuthCommand.cs
Normal file
40
DearFTP/Connection/Commands/AuthCommand.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DearFTP.Connection.Commands
|
||||||
|
{
|
||||||
|
class AuthCommand : ICommand
|
||||||
|
{
|
||||||
|
public string[] Aliases { get; } = new string[]
|
||||||
|
{
|
||||||
|
"AUTH"
|
||||||
|
};
|
||||||
|
|
||||||
|
public void Execute(Session session, FtpStream stream, string alias, string argument)
|
||||||
|
{
|
||||||
|
string protocol = argument.ToUpper();
|
||||||
|
|
||||||
|
if (protocol != "TLS" && protocol != "TLS-C" && protocol != "SSL")
|
||||||
|
{
|
||||||
|
stream.Send(ResponseCode.ArgumentNotImplemented, "Invalid argument, expected 'TLS'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tlsConfiguration = session.Configuration.Tls;
|
||||||
|
|
||||||
|
if (!tlsConfiguration.AllowTls)
|
||||||
|
{
|
||||||
|
session.LogError("Tls", "Client tried to use Tls but Tls is desactivated");
|
||||||
|
stream.Send(ResponseCode.NotImplemented, "Tls is not enabled on this server");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Send(ResponseCode.AcceptAuthenticationMechanism, "Tls activated.");
|
||||||
|
|
||||||
|
session.ActivateTls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ namespace DearFTP.Connection.Commands
|
|||||||
{
|
{
|
||||||
public ICommand[] Commands { get; } = new ICommand[]
|
public ICommand[] Commands { get; } = new ICommand[]
|
||||||
{
|
{
|
||||||
|
new AuthCommand(),
|
||||||
new ClntCommand(),
|
new ClntCommand(),
|
||||||
new CwdCommand(),
|
new CwdCommand(),
|
||||||
new DeleteCommand(),
|
new DeleteCommand(),
|
||||||
@@ -21,6 +22,8 @@ namespace DearFTP.Connection.Commands
|
|||||||
new OptionsCommand(),
|
new OptionsCommand(),
|
||||||
new ParentDirectoryCommand(),
|
new ParentDirectoryCommand(),
|
||||||
new PassiveCommand(),
|
new PassiveCommand(),
|
||||||
|
new ProtectionBufferSizeCommand(),
|
||||||
|
new ProtectionCommand(),
|
||||||
new PwdCommand(),
|
new PwdCommand(),
|
||||||
new QuitCommand(),
|
new QuitCommand(),
|
||||||
new RenameCommand(),
|
new RenameCommand(),
|
||||||
@@ -43,15 +46,21 @@ namespace DearFTP.Connection.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var commandExecutor = Commands.FirstOrDefault(x => x.Aliases.Contains(command, StringComparer.OrdinalIgnoreCase));
|
var commandExecutor = Commands.FirstOrDefault(x => x.Aliases.Contains(command, StringComparer.OrdinalIgnoreCase));
|
||||||
|
var stream = session.FtpStream;
|
||||||
|
|
||||||
if (commandExecutor == null)
|
if (commandExecutor == null)
|
||||||
{
|
{
|
||||||
session.FtpStream.Send(ResponseCode.NotImplemented, $"Command '{command}' not implemented or invalid");
|
stream.Send(ResponseCode.NotImplemented, $"Command '{command}' not implemented or invalid");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandExecutor.Execute(session, session.FtpStream, command, argument);
|
if (session.Configuration.Tls.ForceTls && !session.IsTlsProtected && command.ToUpper() != "AUTH")
|
||||||
|
{
|
||||||
|
stream.Send(ResponseCode.InsufficientProtection, "Not protected connection is not allowed on this server.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandExecutor.Execute(session, stream, command, argument);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,12 @@ namespace DearFTP.Connection.Commands
|
|||||||
(
|
(
|
||||||
ResponseCode.SystemStatusOrHelpReply,
|
ResponseCode.SystemStatusOrHelpReply,
|
||||||
"Features:",
|
"Features:",
|
||||||
|
"AUTH TLS",
|
||||||
"MDTM",
|
"MDTM",
|
||||||
"MLST",
|
"MLST",
|
||||||
"PASV",
|
"PASV",
|
||||||
|
"PBSZ",
|
||||||
|
"PROT",
|
||||||
"REST STREAM",
|
"REST STREAM",
|
||||||
"SIZE",
|
"SIZE",
|
||||||
"TVFS",
|
"TVFS",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace DearFTP.Connection.Commands
|
|||||||
"ABOR",
|
"ABOR",
|
||||||
"ALLO",
|
"ALLO",
|
||||||
"APPE",
|
"APPE",
|
||||||
|
"AUTH",
|
||||||
"CDUP",
|
"CDUP",
|
||||||
"CWD",
|
"CWD",
|
||||||
"DELE",
|
"DELE",
|
||||||
@@ -38,7 +39,9 @@ namespace DearFTP.Connection.Commands
|
|||||||
"OPTS",
|
"OPTS",
|
||||||
"PASS",
|
"PASS",
|
||||||
"PASV",
|
"PASV",
|
||||||
|
"PBSZ",
|
||||||
"PORT",
|
"PORT",
|
||||||
|
"PROT",
|
||||||
"PWD",
|
"PWD",
|
||||||
"QUIT",
|
"QUIT",
|
||||||
"REIN",
|
"REIN",
|
||||||
|
|||||||
25
DearFTP/Connection/Commands/ProtectionBufferSizeCommand.cs
Normal file
25
DearFTP/Connection/Commands/ProtectionBufferSizeCommand.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DearFTP.Connection.Commands
|
||||||
|
{
|
||||||
|
class ProtectionBufferSizeCommand : ICommand
|
||||||
|
{
|
||||||
|
public string[] Aliases { get; } = new string[]
|
||||||
|
{
|
||||||
|
"PBSZ"
|
||||||
|
};
|
||||||
|
|
||||||
|
public void Execute(Session session, FtpStream stream, string alias, string argument)
|
||||||
|
{
|
||||||
|
if (argument != "0")
|
||||||
|
{
|
||||||
|
stream.Send(ResponseCode.ArgumentsError, "Invalid argument, expected '0'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.Send(ResponseCode.OK, "Ok.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
DearFTP/Connection/Commands/ProtectionCommand.cs
Normal file
32
DearFTP/Connection/Commands/ProtectionCommand.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DearFTP.Connection.Commands
|
||||||
|
{
|
||||||
|
class ProtectionCommand : ICommand
|
||||||
|
{
|
||||||
|
public string[] Aliases { get; } = new string[]
|
||||||
|
{
|
||||||
|
"PROT"
|
||||||
|
};
|
||||||
|
|
||||||
|
public void Execute(Session session, FtpStream stream, string alias, string argument)
|
||||||
|
{
|
||||||
|
switch (argument.ToUpper())
|
||||||
|
{
|
||||||
|
case "C":
|
||||||
|
session.DataConnection.DesactivateTsl();
|
||||||
|
stream.Send(ResponseCode.OK, "Data protection cleared.");
|
||||||
|
break;
|
||||||
|
case "P":
|
||||||
|
session.DataConnection.ActivateTsl();
|
||||||
|
stream.Send(ResponseCode.OK, "Data protection set.");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stream.Send(ResponseCode.ArgumentsError, "Invalid argument.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace DearFTP.Connection.Commands
|
|||||||
{
|
{
|
||||||
var dataConnection = session.DataConnection;
|
var dataConnection = session.DataConnection;
|
||||||
|
|
||||||
if (!dataConnection.IsAvailable)
|
if (!dataConnection.IsTslProtected && !dataConnection.IsAvailable)
|
||||||
{
|
{
|
||||||
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
||||||
return;
|
return;
|
||||||
@@ -40,6 +40,12 @@ namespace DearFTP.Connection.Commands
|
|||||||
|
|
||||||
stream.Send(ResponseCode.FileStatusOK, "File coming.");
|
stream.Send(ResponseCode.FileStatusOK, "File coming.");
|
||||||
|
|
||||||
|
if (dataConnection.IsTslProtected && !dataConnection.IsAvailable)
|
||||||
|
{
|
||||||
|
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int restartPosition = session.RestartPosition;
|
int restartPosition = session.RestartPosition;
|
||||||
session.RestartPosition = 0;
|
session.RestartPosition = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace DearFTP.Connection.Commands
|
|||||||
{
|
{
|
||||||
var dataConnection = session.DataConnection;
|
var dataConnection = session.DataConnection;
|
||||||
|
|
||||||
if (!dataConnection.IsAvailable)
|
if (!dataConnection.IsTslProtected && !dataConnection.IsAvailable)
|
||||||
{
|
{
|
||||||
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
||||||
return;
|
return;
|
||||||
@@ -52,6 +52,12 @@ namespace DearFTP.Connection.Commands
|
|||||||
|
|
||||||
stream.Send(ResponseCode.FileStatusOK, "Waiting file.");
|
stream.Send(ResponseCode.FileStatusOK, "Waiting file.");
|
||||||
|
|
||||||
|
if (dataConnection.IsTslProtected && !dataConnection.IsAvailable)
|
||||||
|
{
|
||||||
|
stream.Send(ResponseCode.DataConnectionOpenError, "Passive mode not activated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ReceiveFile(dataConnection.Stream, realPath, alias.ToUpper() == "APPE");
|
ReceiveFile(dataConnection.Stream, realPath, alias.ToUpper() == "APPE");
|
||||||
|
|
||||||
dataConnection.Close();
|
dataConnection.Close();
|
||||||
@@ -59,7 +65,7 @@ namespace DearFTP.Connection.Commands
|
|||||||
stream.Send(ResponseCode.CloseDataConnection, "File received.");
|
stream.Send(ResponseCode.CloseDataConnection, "File received.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReceiveFile(NetworkStream stream, string path, bool append)
|
private void ReceiveFile(Stream stream, string path, bool append)
|
||||||
{
|
{
|
||||||
using (var file = File.Open(path, append ? FileMode.Append : FileMode.Create))
|
using (var file = File.Open(path, append ? FileMode.Append : FileMode.Create))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
using System;
|
using DearFTP.Configurations;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -10,11 +13,12 @@ namespace DearFTP.Connection
|
|||||||
{
|
{
|
||||||
class DataConnection
|
class DataConnection
|
||||||
{
|
{
|
||||||
public const int Timeout = 10_000;
|
public const int Timeout = 100_000;
|
||||||
|
|
||||||
public TcpListener Listener { get; private set; }
|
public TcpListener Listener { get; private set; }
|
||||||
public TcpClient Client { get; private set; }
|
public TcpClient Client { get; private set; }
|
||||||
public NetworkStream Stream { 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
|
public bool IsAvailable
|
||||||
{
|
{
|
||||||
@@ -41,7 +45,7 @@ namespace DearFTP.Connection
|
|||||||
|
|
||||||
public DataConnection()
|
public DataConnection()
|
||||||
{
|
{
|
||||||
|
IsTslProtected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Create()
|
public void Create()
|
||||||
@@ -56,15 +60,36 @@ namespace DearFTP.Connection
|
|||||||
Listener.Start();
|
Listener.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AcceptClient()
|
public void AcceptClient(bool authenticateAfter = false)
|
||||||
{
|
{
|
||||||
_acceptTask = Listener.AcceptTcpClientAsync().ContinueWith(t =>
|
_acceptTask = Listener.AcceptTcpClientAsync().ContinueWith(t =>
|
||||||
{
|
{
|
||||||
Client = t.Result;
|
Client = t.Result;
|
||||||
Stream = Client.GetStream();
|
|
||||||
|
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 ActivateTsl()
|
||||||
|
{
|
||||||
|
IsTslProtected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DesactivateTsl()
|
||||||
|
{
|
||||||
|
IsTslProtected = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
Stream.Close();
|
Stream.Close();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -10,18 +11,18 @@ namespace DearFTP.Connection
|
|||||||
{
|
{
|
||||||
public const int BUFFER_SIZE = 4096;
|
public const int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
public NetworkStream NetworkStream { get; }
|
public Stream Stream { get; }
|
||||||
|
|
||||||
public FtpStream(NetworkStream networkStream)
|
public FtpStream(Stream stream)
|
||||||
{
|
{
|
||||||
NetworkStream = networkStream;
|
Stream = stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (string command, string argument) Receive()
|
public (string command, string argument) Receive()
|
||||||
{
|
{
|
||||||
var buffer = new byte[BUFFER_SIZE];
|
var buffer = new byte[BUFFER_SIZE];
|
||||||
|
|
||||||
int readBytes = NetworkStream.Read(buffer, 0, buffer.Length);
|
int readBytes = Stream.Read(buffer, 0, buffer.Length);
|
||||||
|
|
||||||
if (readBytes == 0)
|
if (readBytes == 0)
|
||||||
{
|
{
|
||||||
@@ -49,14 +50,14 @@ namespace DearFTP.Connection
|
|||||||
{
|
{
|
||||||
var bytes = Encoding.UTF8.GetBytes($"{message}{(end ? "\r\n" : "")}");
|
var bytes = Encoding.UTF8.GetBytes($"{message}{(end ? "\r\n" : "")}");
|
||||||
|
|
||||||
NetworkStream.Write(bytes, 0, bytes.Length);
|
Stream.Write(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(ResponseCode code, string argument)
|
public void Send(ResponseCode code, string argument)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.UTF8.GetBytes($"{(uint)code} {argument}\r\n");
|
var bytes = Encoding.UTF8.GetBytes($"{(uint)code} {argument}\r\n");
|
||||||
|
|
||||||
NetworkStream.Write(bytes, 0, bytes.Length);
|
Stream.Write(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(ResponseCode code, string message, params string[] arguments)
|
public void Send(ResponseCode code, string message, params string[] arguments)
|
||||||
@@ -74,7 +75,7 @@ namespace DearFTP.Connection
|
|||||||
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(builder.ToString());
|
var bytes = Encoding.UTF8.GetBytes(builder.ToString());
|
||||||
|
|
||||||
NetworkStream.Write(bytes, 0, bytes.Length);
|
Stream.Write(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,6 +175,10 @@ namespace DearFTP.Connection
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ArgumentNotImplemented = 504,
|
ArgumentNotImplemented = 504,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Current level of protection is insufficient, need TLS/SSL
|
||||||
|
/// </summary>
|
||||||
|
InsufficientProtection = 522,
|
||||||
|
/// <summary>
|
||||||
/// Not logged in.
|
/// Not logged in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NotLoggedIn = 530,
|
NotLoggedIn = 530,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -20,14 +21,17 @@ namespace DearFTP.Connection
|
|||||||
public Share[] Shares { get; set; }
|
public Share[] Shares { get; set; }
|
||||||
public Share[] WritablesShares { get; set; }
|
public Share[] WritablesShares { get; set; }
|
||||||
public NavigablePath NavigablePath { get; set; }
|
public NavigablePath NavigablePath { get; set; }
|
||||||
public FtpStream FtpStream { get; }
|
public FtpStream FtpStream { get; private set; }
|
||||||
public DataConnection DataConnection { get; set; }
|
public DataConnection DataConnection { get; set; }
|
||||||
public int RestartPosition { get; set; }
|
public int RestartPosition { get; set; }
|
||||||
|
public bool IsTlsProtected { get; private set; }
|
||||||
public string CurrentWorkingDirectory => NavigablePath.CurrentDirectory;
|
public string CurrentWorkingDirectory => NavigablePath.CurrentDirectory;
|
||||||
|
|
||||||
public string IP => ((IPEndPoint)_client.Client.LocalEndPoint).Address.ToString();
|
public string IP => ((IPEndPoint)_client.Client.LocalEndPoint).Address.ToString();
|
||||||
|
|
||||||
private TcpClient _client;
|
private TcpClient _client;
|
||||||
private NetworkStream _networkStream;
|
private NetworkStream _networkStream;
|
||||||
|
private SslStream _sslStream;
|
||||||
private bool _isRunning = true;
|
private bool _isRunning = true;
|
||||||
|
|
||||||
public Session(TcpClient client)
|
public Session(TcpClient client)
|
||||||
@@ -41,6 +45,7 @@ namespace DearFTP.Connection
|
|||||||
Logger = FtpServer.Instance.Logger;
|
Logger = FtpServer.Instance.Logger;
|
||||||
DataConnection = new DataConnection();
|
DataConnection = new DataConnection();
|
||||||
RestartPosition = 0;
|
RestartPosition = 0;
|
||||||
|
IsTlsProtected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
@@ -50,7 +55,7 @@ namespace DearFTP.Connection
|
|||||||
while (_isRunning)
|
while (_isRunning)
|
||||||
{
|
{
|
||||||
(string command, string argument) = FtpStream.Receive();
|
(string command, string argument) = FtpStream.Receive();
|
||||||
Logger.Log($"[{_client.Client.RemoteEndPoint}]: {command} {argument}");
|
Log($"{command} {argument}");
|
||||||
|
|
||||||
CommandsDispatcher.Dispatch(this, command, argument);
|
CommandsDispatcher.Dispatch(this, command, argument);
|
||||||
}
|
}
|
||||||
@@ -63,29 +68,30 @@ namespace DearFTP.Connection
|
|||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetRealPath(string path)
|
public void Log(string message)
|
||||||
{
|
{
|
||||||
string completePath = Path.Combine(CurrentWorkingDirectory, path);
|
Logger.Log($"[{_client.Client.RemoteEndPoint}]: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
string[] split = CurrentWorkingDirectory.Substring(1).Split('/');
|
public void LogError(string error, string description)
|
||||||
|
{
|
||||||
|
Logger.LogError(error, $"[{_client.Client.RemoteEndPoint}]: {description}");
|
||||||
|
}
|
||||||
|
|
||||||
if (split.Length == 0)
|
public void ActivateTls()
|
||||||
{
|
{
|
||||||
return null;
|
_sslStream = new SslStream(_networkStream, true);
|
||||||
}
|
|
||||||
|
|
||||||
var share = Shares.FirstOrDefault(x => x.Name == split[0]);
|
_sslStream.AuthenticateAsServer(Configuration.Tls.X509Certificate, false, true);
|
||||||
|
|
||||||
if (share == null)
|
FtpStream = new FtpStream(_sslStream);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Path.Combine(split.Skip(1).Prepend(share.Path).ToArray());
|
IsTlsProtected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_sslStream?.Close();
|
||||||
_networkStream.Close();
|
_networkStream.Close();
|
||||||
_client.Close();
|
_client.Close();
|
||||||
}
|
}
|
||||||
|
|||||||
1070
DearFTP/Utils/OpenSslKey.cs
Normal file
1070
DearFTP/Utils/OpenSslKey.cs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user