diff --git a/docs/Server-configuration.md b/docs/Server-configuration.md index 61891296..6252b981 100644 --- a/docs/Server-configuration.md +++ b/docs/Server-configuration.md @@ -40,6 +40,8 @@ Impostor has an Anticheat that makes it possible to kick cheaters from games aut | **EnableRoleChecks** | `true` | Enables checks that check if players have the correct role when performing certain role abilities like venting or murdering. | | **EnableTargetChecks** | `true` | Enables checks that check if certain packets to everyone that should only have been sent to certain players or vice versa. This includes sending votes or network objects. | | **ForbidProtocolExtensions** | `true` | If disabled allows players to send network packets that go beyond the network packets sent by the vanilla game. This is necessary for most mods that need all players to install it. | +| **EnablePacketSizeChecks** | `true` | Enables checks that verify if network messages exceed the maximum allowed size. | +| **PacketSizeLimit** | `1203` | The maximum allowed size (in bytes) for a network message. The official servers of Among Us requires that a Hazel packet is < 1204 bytes, excluding headers. | ### Compatibility diff --git a/src/Impostor.Api/CheatCategory.cs b/src/Impostor.Api/CheatCategory.cs index 26f6c5a6..5b890060 100644 --- a/src/Impostor.Api/CheatCategory.cs +++ b/src/Impostor.Api/CheatCategory.cs @@ -32,6 +32,9 @@ public enum CheatCategory /// A packet was sent on an invalid network object, like a PlayerControl without PlayerInfo. InvalidObject, + /// A packet was sent that exceeded the maximum allowed RPC size. + PacketSize, + /// Legacy category for unsorted anticheat checks. Other, } diff --git a/src/Impostor.Api/Config/AntiCheatConfig.cs b/src/Impostor.Api/Config/AntiCheatConfig.cs index a6499040..a9233068 100644 --- a/src/Impostor.Api/Config/AntiCheatConfig.cs +++ b/src/Impostor.Api/Config/AntiCheatConfig.cs @@ -29,5 +29,9 @@ namespace Impostor.Api.Config public bool EnableTargetChecks { get; set; } = true; public bool ForbidProtocolExtensions { get; set; } = true; + + public bool EnablePacketSizeChecks { get; set; } = true; + + public int PacketSizeLimit { get; set; } = 1203; } } diff --git a/src/Impostor.Server/Net/Client.cs b/src/Impostor.Server/Net/Client.cs index 08597c22..65d8e496 100644 --- a/src/Impostor.Server/Net/Client.cs +++ b/src/Impostor.Server/Net/Client.cs @@ -80,6 +80,7 @@ namespace Impostor.Server.Net CheatingHostMode.Never => true, _ => true, }, + CheatCategory.PacketSize => _antiCheatConfig.EnablePacketSizeChecks, CheatCategory.Other => true, _ => LogUnknownCategory(category), }; diff --git a/src/Impostor.Server/Net/Hazel/HazelConnection.cs b/src/Impostor.Server/Net/Hazel/HazelConnection.cs index 47c094f4..3033cfb1 100644 --- a/src/Impostor.Server/Net/Hazel/HazelConnection.cs +++ b/src/Impostor.Server/Net/Hazel/HazelConnection.cs @@ -1,18 +1,23 @@ using System.Net; using System.Threading.Tasks; +using Impostor.Api; +using Impostor.Api.Config; using Impostor.Api.Net; using Impostor.Hazel; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace Impostor.Server.Net.Hazel { internal class HazelConnection : IHazelConnection { private readonly ILogger _logger; + private readonly AntiCheatConfig _antiCheatConfig; - public HazelConnection(Connection innerConnection, ILogger logger) + public HazelConnection(Connection innerConnection, ILogger logger, IOptions antiCheatOptions) { _logger = logger; + _antiCheatConfig = antiCheatOptions.Value; InnerConnection = innerConnection; innerConnection.DataReceived = ConnectionOnDataReceived; innerConnection.Disconnected = ConnectionOnDisconnected; @@ -58,6 +63,19 @@ namespace Impostor.Server.Net.Hazel return; } + // Check raw message size against the configured limit. + // Innersloth requires full packet ≤ 1200 bytes (1168 bytes payload after 32 bytes IP+UDP headers). + if (e.Message.Length > _antiCheatConfig.PacketSizeLimit) + { + if (await Client.ReportCheatAsync( + new CheatContext("RootMessage"), + CheatCategory.PacketSize, + $"Received a message that is too large, length: {e.Message.Length}")) + { + return; + } + } + while (true) { if (e.Message.Position >= e.Message.Length) diff --git a/src/Impostor.Server/Net/Matchmaker.cs b/src/Impostor.Server/Net/Matchmaker.cs index a8682bf6..55b76ea6 100644 --- a/src/Impostor.Server/Net/Matchmaker.cs +++ b/src/Impostor.Server/Net/Matchmaker.cs @@ -2,6 +2,7 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks; +using Impostor.Api.Config; using Impostor.Api.Events.Managers; using Impostor.Api.Net.Messages.C2S; using Impostor.Hazel; @@ -11,6 +12,7 @@ using Impostor.Server.Net.Hazel; using Impostor.Server.Net.Manager; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.Options; namespace Impostor.Server.Net { @@ -20,18 +22,21 @@ namespace Impostor.Server.Net private readonly ClientManager _clientManager; private readonly ObjectPool _readerPool; private readonly ILogger _connectionLogger; + private readonly IOptions _antiCheatOptions; private UdpConnectionListener? _connection; public Matchmaker( IEventManager eventManager, ClientManager clientManager, ObjectPool readerPool, - ILogger connectionLogger) + ILogger connectionLogger, + IOptions antiCheatOptions) { _eventManager = eventManager; _clientManager = clientManager; _readerPool = readerPool; _connectionLogger = connectionLogger; + _antiCheatOptions = antiCheatOptions; } public async ValueTask StartAsync(IPEndPoint ipEndPoint) @@ -64,7 +69,7 @@ namespace Impostor.Server.Net // Handshake. HandshakeC2S.Deserialize(e.HandshakeData, out var clientVersion, out var name, out var language, out var chatMode, out var platformSpecificData); - var connection = new HazelConnection(e.Connection, _connectionLogger); + var connection = new HazelConnection(e.Connection, _connectionLogger, _antiCheatOptions); await _eventManager.CallAsync(new ClientConnectionEvent(connection, e.HandshakeData)); diff --git a/src/Impostor.Server/config.json b/src/Impostor.Server/config.json index 68d2dc97..cdd37908 100644 --- a/src/Impostor.Server/config.json +++ b/src/Impostor.Server/config.json @@ -21,7 +21,9 @@ "EnableOwnershipChecks": true, "EnableRoleChecks": true, "EnableTargetChecks": true, - "ForbidProtocolExtensions": true + "ForbidProtocolExtensions": true, + "EnablePacketSizeChecks": true, + "PacketSizeLimit": 1203 }, "Timeout": { "SpawnTimeout": 2500,