From 2cad4ffa1488fe6de8adbe10350f18325ddf0bdc Mon Sep 17 00:00:00 2001 From: Christina <122680126+HayashiUme@users.noreply.github.com> Date: Sun, 21 Jun 2026 17:17:05 +0800 Subject: [PATCH] Added an RPC packet size anti-cheat check with config (#731) * Added an RPC packet size anti-cheat * Support PackedGameDataTo * Move packet size check to HazelConnection * Update PacketSizeLimit to 1153 and add anti-cheat docs * Change default to value determined on officials Thanks Niko for doing the research --------- Co-authored-by: miniduikboot Co-authored-by: NikoCat233 <139348239+NikoCat233@users.noreply.github.com> --- docs/Server-configuration.md | 2 ++ src/Impostor.Api/CheatCategory.cs | 3 +++ src/Impostor.Api/Config/AntiCheatConfig.cs | 4 ++++ src/Impostor.Server/Net/Client.cs | 1 + .../Net/Hazel/HazelConnection.cs | 20 ++++++++++++++++++- src/Impostor.Server/Net/Matchmaker.cs | 9 +++++++-- src/Impostor.Server/config.json | 4 +++- 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/Server-configuration.md b/docs/Server-configuration.md index 6189129..6252b98 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 26f6c5a..5b89006 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 a649904..a923306 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 08597c2..65d8e49 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 47c094f..3033cfb 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 a8682bf..55b76ea 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 68d2dc9..cdd3790 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, -- 2.39.5