From a39fae332551b3ebf1112d90d064dcbe2be2c626 Mon Sep 17 00:00:00 2001 From: js6pak Date: Sat, 3 Apr 2021 00:07:06 +0200 Subject: [PATCH] Initial auth implementation --- .../Net/Messages/Auth/Message01Complete.cs | 15 ++++ .../Net/Messages/Auth/MessageHandshake.cs | 14 +++ .../Config/AuthServerConfig.cs | 27 ++++++ src/Impostor.Server/Net/AuthService.cs | 88 +++++++++++++++++++ src/Impostor.Server/Net/Matchmaker.cs | 2 +- src/Impostor.Server/Program.cs | 10 +++ 6 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs create mode 100644 src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs create mode 100644 src/Impostor.Server/Config/AuthServerConfig.cs create mode 100644 src/Impostor.Server/Net/AuthService.cs diff --git a/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs b/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs new file mode 100644 index 0000000..2572f8c --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Auth/Message01Complete.cs @@ -0,0 +1,15 @@ +namespace Impostor.Api.Net.Messages.Auth +{ + public static class Message01Complete + { + public static void Serialize(IMessageWriter writer, uint nonce) + { + writer.WritePacked(nonce); + } + + public static void Deserialize(IMessageReader reader, out uint nonce) + { + nonce = reader.ReadUInt32(); + } + } +} diff --git a/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs b/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs new file mode 100644 index 0000000..146d004 --- /dev/null +++ b/src/Impostor.Api/Net/Messages/Auth/MessageHandshake.cs @@ -0,0 +1,14 @@ +using Impostor.Api.Innersloth; + +namespace Impostor.Api.Net.Messages.Auth +{ + public static class MessageHandshake + { + public static void Deserialize(IMessageReader reader, out int clientVersion, out Platforms platform, out string clientId) + { + clientVersion = reader.ReadInt32(); + platform = (Platforms)reader.ReadByte(); + clientId = reader.ReadString(); + } + } +} diff --git a/src/Impostor.Server/Config/AuthServerConfig.cs b/src/Impostor.Server/Config/AuthServerConfig.cs new file mode 100644 index 0000000..72c8efe --- /dev/null +++ b/src/Impostor.Server/Config/AuthServerConfig.cs @@ -0,0 +1,27 @@ +using System.IO; +using Impostor.Server.Utils; + +namespace Impostor.Server.Config +{ + internal class AuthServerConfig + { + public const string Section = "AuthServer"; + + private string? _resolvedListenIp; + + public bool Enabled { get; set; } = false; + + public string ListenIp { get; set; } = "0.0.0.0"; + + public ushort ListenPort { get; set; } = 22025; + + public string Certificate { get; set; } = Path.Combine("dtls", "certificate.pem"); + + public string PrivateKey { get; set; } = Path.Combine("dtls", "key.pem"); + + public string ResolveListenIp() + { + return _resolvedListenIp ??= IpUtils.ResolveIp(ListenIp); + } + } +} diff --git a/src/Impostor.Server/Net/AuthService.cs b/src/Impostor.Server/Net/AuthService.cs new file mode 100644 index 0000000..c8a95b2 --- /dev/null +++ b/src/Impostor.Server/Net/AuthService.cs @@ -0,0 +1,88 @@ +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; +using Impostor.Api.Events.Managers; +using Impostor.Api.Net.Messages; +using Impostor.Api.Net.Messages.Auth; +using Impostor.Hazel; +using Impostor.Hazel.Dtls; +using Impostor.Server.Config; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.Options; + +namespace Impostor.Server.Net +{ + internal class AuthService : IHostedService + { + private readonly ILogger _logger; + private readonly AuthServerConfig _config; + private readonly ObjectPool _readerPool; + private readonly IEventManager _eventManager; + private DtlsConnectionListener? _connection; + + public AuthService(ILogger logger, IOptions config, ObjectPool readerPool, IEventManager eventManager) + { + _logger = logger; + _config = config.Value; + _readerPool = readerPool; + _eventManager = eventManager; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + var endpoint = new IPEndPoint(IPAddress.Parse(_config.ResolveListenIp()), _config.ListenPort); + + var mode = endpoint.AddressFamily switch + { + AddressFamily.InterNetwork => IPMode.IPv4, + AddressFamily.InterNetworkV6 => IPMode.IPv6, + _ => throw new InvalidOperationException(), + }; + + var rsa = RSA.Create(); + rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(string.Join(string.Empty, (await File.ReadAllLinesAsync(_config.PrivateKey, cancellationToken)).Where(x => !x.StartsWith("-----")))), out _); + var cert = new X509Certificate2(_config.Certificate).CopyWithPrivateKey(rsa); + + _connection = new DtlsConnectionListener(endpoint, _readerPool, mode); + _connection.SetCertificate(cert); + _connection.NewConnection = ConnectionOnNewConnection; + + await _connection.StartAsync(); + + _logger.LogInformation("Auth server is listening on {Address}:{Port}", endpoint.Address, endpoint.Port); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + _logger.LogWarning("Auth server is shutting down!"); + + if (_connection != null) + { + await _connection.DisposeAsync(); + } + } + + private ValueTask ConnectionOnNewConnection(NewConnectionEventArgs e) + { + MessageHandshake.Deserialize(e.HandshakeData, out var clientVersion, out var platform, out var clientId); + + _logger.LogTrace("New authentication request: {clientVersion}, {platform}, {clientId}", clientVersion, platform, clientId); + + using var writer = MessageWriter.Get(MessageType.Reliable); + + writer.StartMessage(1); + Message01Complete.Serialize(writer, (uint)RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue)); + writer.EndMessage(); + + return e.Connection.SendAsync(writer); + } + } +} diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index e7ce3ac..6af4f55 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -61,7 +61,7 @@ namespace Impostor.Server.Net private async ValueTask OnNewConnection(NewConnectionEventArgs e) { // Handshake. - HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name); + HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out _); var connection = new HazelConnection(e.Connection, _connectionLogger); diff --git a/src/Impostor.Server/Program.cs b/src/Impostor.Server/Program.cs index 03514d9..d82a236 100644 --- a/src/Impostor.Server/Program.cs +++ b/src/Impostor.Server/Program.cs @@ -117,6 +117,10 @@ namespace Impostor.Server .GetSection(AnnouncementsServerConfig.Section) .Get() ?? new AnnouncementsServerConfig(); + var authServer = host.Configuration + .GetSection(AuthServerConfig.Section) + .Get() ?? new AuthServerConfig(); + services.AddSingleton(); services.AddSingleton(); @@ -124,6 +128,7 @@ namespace Impostor.Server services.Configure(host.Configuration.GetSection(AntiCheatConfig.Section)); services.Configure(host.Configuration.GetSection(ServerConfig.Section)); services.Configure(host.Configuration.GetSection(AnnouncementsServerConfig.Section)); + services.Configure(host.Configuration.GetSection(AuthServerConfig.Section)); services.Configure(host.Configuration.GetSection(ServerRedirectorConfig.Section)); if (redirector.Enabled) @@ -212,6 +217,11 @@ namespace Impostor.Server { services.AddHostedService(); } + + if (authServer.Enabled) + { + services.AddHostedService(); + } }) .UseSerilog() .UseConsoleLifetime() -- 2.39.5