Skip to content

Commit

Permalink
feat: implement service for manipulating intercepted packets
Browse files Browse the repository at this point in the history
  • Loading branch information
ArachisH committed Mar 8, 2024
1 parent 80ddbf4 commit 6cdce04
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 28 deletions.
9 changes: 6 additions & 3 deletions Tanji.CLI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ static void CleanUp(PosixSignalContext context)

private readonly ILogger<Program> _logger;
private readonly IWebInterceptionService _webInterception;
private readonly IConnectionHandlerService _connectionHandler;
private readonly IClientHandlerService<CachedGame> _clientHandler;
private readonly IConnectionHandlerService<PacketMiddlemanService> _connectionHandler;

public Program(ILogger<Program> logger, IWebInterceptionService webInterception, IClientHandlerService<CachedGame> clientHandler, IConnectionHandlerService connectionHandler)
public Program(ILogger<Program> logger,
IWebInterceptionService webInterception,
IClientHandlerService<CachedGame> clientHandler,
IConnectionHandlerService<PacketMiddlemanService> connectionHandler)
{
_logger = logger;
_clientHandler = clientHandler;
Expand All @@ -71,7 +74,7 @@ public async Task RunAsync(CancellationToken cancellationToken = default)
_logger.LogInformation("Client Processed : {game.path}", game.Path);

var connectionContext = new HConnectionContext(game);
HConnection connection = await _connectionHandler.LaunchAndInterceptConnectionAsync(ticket, connectionContext, cancellationToken).ConfigureAwait(false);
HConnection<PacketMiddlemanService> connection = await _connectionHandler.LaunchAndInterceptConnectionAsync(ticket, connectionContext, cancellationToken).ConfigureAwait(false);

await connection.WeldNodesAsync(cancellationToken).ConfigureAwait(false);
}
Expand Down
5 changes: 3 additions & 2 deletions Tanji.Core/API/IInstaller.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using Tanji.Core.Habbo.Canvas;
using Tanji.Core.Services;
using Tanji.Core.Habbo.Canvas;
using Tanji.Core.Habbo.Network;

namespace Tanji.Core.API;

public interface IInstaller
{
IGame Game { get; }
IHConnection Connection { get; }
IHConnection<IPacketMiddlemanService> Connection { get; }
}
8 changes: 6 additions & 2 deletions Tanji.Core/Habbo/Network/IHConnection.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
namespace Tanji.Core.Habbo.Network;
using Tanji.Core.Services;

public interface IHConnection
namespace Tanji.Core.Habbo.Network;

public interface IHConnection<TMiddleman> where TMiddleman : IPacketMiddlemanService
{
HNode? Local { get; }
HNode? Remote { get; }

Incoming? In { get; }
Outgoing? Out { get; }

TMiddleman? Middleman { get; }
}
33 changes: 27 additions & 6 deletions Tanji.Core/Network/HConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Net.Sockets;

using Tanji.Core.Habbo;
using Tanji.Core.Services;
using Tanji.Core.Habbo.Network;

using CommunityToolkit.HighPerformance.Buffers;
Expand All @@ -12,7 +13,7 @@ namespace Tanji.Core.Network;
/// <summary>
/// Represents a reusable 'bridge' that transfers data to/from two separate <see cref="HNode"/> instances.
/// </summary>
public sealed class HConnection : IHConnection
public sealed class HConnection<TMiddleman> : IHConnection<TMiddleman> where TMiddleman : IPacketMiddlemanService
{
private static ReadOnlySpan<byte> XDPRequestBytes => "<policy-file-request/>\0"u8;
private static readonly ReadOnlyMemory<byte> XDPResponseBytes = Encoding.UTF8.GetBytes("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy>\0");
Expand All @@ -25,12 +26,21 @@ public sealed class HConnection : IHConnection
public Incoming? In { get; set; }
public Outgoing? Out { get; set; }

public TMiddleman? Middleman { get; }
public bool IsConnected => Local != null && Remote != null && Local.IsConnected & Remote.IsConnected;

public HConnection()
: this(default)
{ }
public HConnection(TMiddleman? middleman)
{
Middleman = middleman;
}

public Task WeldNodesAsync(CancellationToken cancellationToken = default)
{
Task localToRemote = WeldNodesAsync(Local!, Remote!, true, cancellationToken);
Task remoteToLocal = WeldNodesAsync(Remote!, Local!, false, cancellationToken);
Task localToRemote = WeldNodesAsync(Local!, Remote!, Middleman, true, cancellationToken);
Task remoteToLocal = WeldNodesAsync(Remote!, Local!, Middleman, false, cancellationToken);
return Task.WhenAll(localToRemote, remoteToLocal);
}
public async ValueTask InterceptLocalConnectionAsync(HConnectionContext context, CancellationToken cancellationToken = default)
Expand Down Expand Up @@ -164,7 +174,8 @@ private static async ValueTask<Socket> ConnectAsync(EndPoint remoteEndPoint, Can
}
return socket;
}
private static async Task WeldNodesAsync(HNode source, HNode destination, bool isOutbound, CancellationToken cancellationToken = default)

private static async Task WeldNodesAsync(HNode source, HNode destination, TMiddleman? middleman, bool isOutbound, CancellationToken cancellationToken = default)
{
while (source.IsConnected && destination.IsConnected && !cancellationToken.IsCancellationRequested)
{
Expand All @@ -173,16 +184,26 @@ private static async Task WeldNodesAsync(HNode source, HNode destination, bool i
_ = await source.ReceivePacketAsync(bufferWriter, cancellationToken).ConfigureAwait(false);

// Continuously attempt to receive packets from the node
_ = TransferPacketAsync(destination, bufferWriter, isOutbound, cancellationToken);
_ = TransferPacketAsync(destination, bufferWriter, middleman, isOutbound, cancellationToken);
}
}
private static async Task TransferPacketAsync(HNode destination, ArrayPoolBufferWriter<byte> bufferWriter, bool isOutbound, CancellationToken cancellationToken = default)
private static async Task TransferPacketAsync(HNode destination, ArrayPoolBufferWriter<byte> bufferWriter, TMiddleman? middleman, bool isOutbound, CancellationToken cancellationToken = default)
{
try
{
if (bufferWriter.WrittenCount == 0) return;
Memory<byte> mutableBuffer = bufferWriter.DangerousGetArray();

if (middleman != null)
{
ValueTask<bool> packetProcessTask = isOutbound
? middleman.PacketOutboundAsync(mutableBuffer)
: middleman.PacketInboundAsync(mutableBuffer);

// If true, the packet is to be ignored/blocked
if (await packetProcessTask.ConfigureAwait(false)) return;
}

await destination.SendPacketAsync(mutableBuffer, cancellationToken).ConfigureAwait(false);
}
finally { bufferWriter.Dispose(); }
Expand Down
6 changes: 0 additions & 6 deletions Tanji.Core/Network/IPacketMiddleman.cs

This file was deleted.

4 changes: 3 additions & 1 deletion Tanji.Core/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ public static IServiceCollection AddTanjiCore(this IServiceCollection services)

// Services
services.AddSingleton<IWebInterceptionService, WebInterceptionService>();
services.AddSingleton<IConnectionHandlerService, ConnectionHandlerService>();
services.AddSingleton<IClientHandlerService<CachedGame>, ClientHandlerService>();

services.AddSingleton<PacketMiddlemanService>();
services.AddSingleton<IConnectionHandlerService<PacketMiddlemanService>, ConnectionHandlerService>();

// Add view-models
services.AddSingleton<ConnectionViewModel>();
services.AddSingleton<InjectionViewModel>();
Expand Down
6 changes: 3 additions & 3 deletions Tanji.Core/Services/IConnectionHandlerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Tanji.Core.Services;

public interface IConnectionHandlerService
public interface IConnectionHandlerService<TPacketMiddleman> where TPacketMiddleman : IPacketMiddlemanService
{
ObservableCollection<HConnection> Connections { get; }
ObservableCollection<HConnection<TPacketMiddleman>> Connections { get; }

Task<HConnection> LaunchAndInterceptConnectionAsync(string ticket, HConnectionContext options, CancellationToken cancellationToken = default);
Task<HConnection<TPacketMiddleman>> LaunchAndInterceptConnectionAsync(string ticket, HConnectionContext options, CancellationToken cancellationToken = default);
}
7 changes: 7 additions & 0 deletions Tanji.Core/Services/IPacketMiddlemanService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Tanji.Core.Services;

public interface IPacketMiddlemanService
{
ValueTask<bool> PacketInboundAsync(Memory<byte> buffer);
ValueTask<bool> PacketOutboundAsync(Memory<byte> buffer);
}
14 changes: 9 additions & 5 deletions Tanji.Core/Services/Implementations/ConnectionHandlerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,32 @@

namespace Tanji.Core.Services;

public sealed class ConnectionHandlerService : IConnectionHandlerService
public sealed class ConnectionHandlerService : IConnectionHandlerService<PacketMiddlemanService>
{
private readonly PacketMiddlemanService _packetMiddleman;
private readonly ILogger<ConnectionHandlerService> _logger;
private readonly IClientHandlerService<CachedGame> _clientHandler;

public ObservableCollection<HConnection> Connections { get; } = [];
public ObservableCollection<HConnection<PacketMiddlemanService>> Connections { get; } = [];

public ConnectionHandlerService(ILogger<ConnectionHandlerService> logger, IClientHandlerService<CachedGame> clientHandler)
public ConnectionHandlerService(ILogger<ConnectionHandlerService> logger,
IClientHandlerService<CachedGame> clientHandler,
PacketMiddlemanService packetMiddleman)
{
_logger = logger;
_clientHandler = clientHandler;
_packetMiddleman = packetMiddleman;
}

public async Task<HConnection> LaunchAndInterceptConnectionAsync(string ticket, HConnectionContext context, CancellationToken cancellationToken = default)
public async Task<HConnection<PacketMiddlemanService>> LaunchAndInterceptConnectionAsync(string ticket, HConnectionContext context, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(ticket))
{
_logger.LogError("Ticket should be provided when attempting to launch the client.");
ThrowHelper.ThrowArgumentNullException(nameof(ticket));
}

var connection = new HConnection();
var connection = new HConnection<PacketMiddlemanService>(_packetMiddleman);
ValueTask interceptLocalConnectionTask = connection.InterceptLocalConnectionAsync(context, cancellationToken);

_ = _clientHandler.LaunchClient(context.Platform, ticket, context.ClientPath);
Expand Down
13 changes: 13 additions & 0 deletions Tanji.Core/Services/Implementations/PacketMiddlemanService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Tanji.Core.Services;

public class PacketMiddlemanService : IPacketMiddlemanService
{
public ValueTask<bool> PacketInboundAsync(Memory<byte> buffer)
{
throw new NotImplementedException();
}
public ValueTask<bool> PacketOutboundAsync(Memory<byte> buffer)
{
throw new NotImplementedException();
}
}

0 comments on commit 6cdce04

Please sign in to comment.