crash ignored players

Otherwise they keep sending all their packets (including positional updates) to the server which costs bandwidth and processing power.
This commit is contained in:
Robin C. Ladiges 2024-04-27 17:46:18 +02:00 committed by Sanae
parent 9511d07f09
commit 082e480b1e
4 changed files with 54 additions and 32 deletions

View File

@ -148,30 +148,27 @@ public static class BanLists {
public static void Crash(
Client user,
bool permanent = false,
bool dispose_user = true,
int delay_ms = 0
int delay_ms = 0
) {
user.Ignored = true;
Task.Run(async () => {
if (delay_ms > 0) {
await Task.Delay(delay_ms);
}
bool permanent = user.Banned;
await user.Send(new ChangeStagePacket {
Id = (permanent ? "$agogus/ban4lyfe" : "$among$us/cr4sh%"),
Stage = (permanent ? "$ejected" : "$agogusStage"),
Scenario = (sbyte) (permanent ? 69 : 21),
SubScenarioType = (byte) (permanent ? 21 : 69),
});
if (dispose_user) {
user.Dispose();
}
});
}
private static void CrashMultiple(string[] args, MUCH much) {
foreach (Client user in much(args).toActUpon) {
Crash(user, true);
user.Banned = true;
Crash(user);
}
}
@ -245,8 +242,9 @@ public static class BanLists {
}
foreach (Client user in res.toActUpon) {
user.Banned = true;
BanClient(user);
Crash(user, true);
Crash(user);
}
Save();

View File

@ -13,6 +13,7 @@ public class Client : IDisposable {
public readonly ConcurrentDictionary<string, object?> Metadata = new ConcurrentDictionary<string, object?>(); // can be used to store any information about a player
public bool Connected = false;
public bool Ignored = false;
public bool Banned = false;
public CostumePacket? CurrentCostume = null; // required for proper client sync
public string Name {
get => Logger.Name;
@ -52,6 +53,11 @@ public class Client : IDisposable {
PacketAttribute packetAttribute = Constants.PacketMap[typeof(T)];
try {
// don't send most packets to ignored players
if (Ignored && packetAttribute.Type != PacketType.Init && packetAttribute.Type != PacketType.ChangeStage) {
memory.Dispose();
return;
}
Server.FillPacket(new PacketHeader {
Id = sender?.Id ?? Id,
Type = packetAttribute.Type,
@ -71,11 +77,16 @@ public class Client : IDisposable {
PacketHeader header = new PacketHeader();
header.Deserialize(data.Span);
if (!Connected && header.Type is not PacketType.Connect) {
if (!Connected && !Ignored && header.Type != PacketType.Connect) {
Server.Logger.Error($"Didn't send {header.Type} to {Id} because they weren't connected yet");
return;
}
// don't send most packets to ignored players
if (Ignored && header.Type != PacketType.Init && header.Type != PacketType.ChangeStage) {
return;
}
await Socket!.SendAsync(data[..(Constants.HeaderSize + header.PacketSize)], SocketFlags.None);
}

View File

@ -120,10 +120,17 @@ void logError(Task x) {
server.PacketHandler = (c, p) => {
switch (p) {
case GamePacket gamePacket: {
// crash ignored player
if (c.Ignored) {
c.Logger.Info($"Crashing ignored player after entering stage {gamePacket.Stage}.");
BanLists.Crash(c, 500);
return false;
}
// crash player entering a banned stage
if (BanLists.Enabled && BanLists.IsStageBanned(gamePacket.Stage)) {
c.Logger.Warn($"Crashing player for entering banned stage {gamePacket.Stage}.");
BanLists.Crash(c, false, false, 500);
BanLists.Crash(c, 500);
return false;
}
@ -172,6 +179,11 @@ server.PacketHandler = (c, p) => {
break;
}
// ignore all other packets from ignored players
case IPacket pack when c.Ignored: {
return false;
}
case TagPacket tagPacket: {
// c.Logger.Info($"Got tag packet: {tagPacket.IsIt}");
if ((tagPacket.UpdateType & TagPacket.TagUpdate.State) != 0) c.Metadata["seeking"] = tagPacket.IsIt;

View File

@ -29,12 +29,6 @@ public class Server {
Socket socket = token.HasValue ? await serverSocket.AcceptAsync(token.Value) : await serverSocket.AcceptAsync();
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
// is the IPv4 address banned?
if (BanLists.Enabled && BanLists.IsIPv4Banned(((IPEndPoint) socket.RemoteEndPoint!).Address!)) {
Logger.Warn($"Ignoring banned IPv4 address {socket.RemoteEndPoint}");
continue;
}
Logger.Warn($"Accepted connection for client {socket.RemoteEndPoint}");
// start sub thread to handle client
@ -80,7 +74,7 @@ public class Server {
public delegate void PacketReplacer<in T>(Client from, Client to, T value); // replacer must send
public void BroadcastReplace<T>(T packet, Client sender, PacketReplacer<T> packetReplacer) where T : struct, IPacket {
foreach (Client client in Clients.Where(client => client.Connected && sender.Id != client.Id)) {
foreach (Client client in Clients.Where(c => c.Connected && !c.Ignored && sender.Id != c.Id)) {
packetReplacer(sender, client, packet);
}
}
@ -97,7 +91,7 @@ public class Server {
}
public Task Broadcast<T>(T packet) where T : struct, IPacket {
return Task.WhenAll(Clients.Where(c => c.Connected).Select(async client => {
return Task.WhenAll(Clients.Where(c => c.Connected && !c.Ignored).Select(async client => {
IMemoryOwner<byte> memory = MemoryPool<byte>.Shared.RentZero(Constants.HeaderSize + packet.Size);
PacketHeader header = new PacketHeader {
Id = client.Id,
@ -116,7 +110,7 @@ public class Server {
/// <param name="data">Memory owner to dispose once done</param>
/// <param name="sender">Optional sender to not broadcast data to</param>
public async Task Broadcast(IMemoryOwner<byte> data, Client? sender = null) {
await Task.WhenAll(Clients.Where(c => c.Connected && c != sender).Select(client => client.Send(data.Memory, sender)));
await Task.WhenAll(Clients.Where(c => c.Connected && !c.Ignored && c != sender).Select(client => client.Send(data.Memory, sender)));
data.Dispose();
}
@ -126,7 +120,7 @@ public class Server {
/// <param name="data">Memory to send to the clients</param>
/// <param name="sender">Optional sender to not broadcast data to</param>
public async void Broadcast(Memory<byte> data, Client? sender = null) {
await Task.WhenAll(Clients.Where(c => c.Connected && c != sender).Select(client => client.Send(data, sender)));
await Task.WhenAll(Clients.Where(c => c.Connected && !c.Ignored && c != sender).Select(client => client.Send(data, sender)));
}
public Client? FindExistingClient(Guid id) {
@ -175,10 +169,6 @@ public class Server {
break;
}
}
if (client.Ignored) {
memory.Dispose();
continue;
}
// connection initialization
if (first) {
@ -195,19 +185,30 @@ public class Server {
client.Id = header.Id;
client.Name = connect.ClientName;
// is the profile ID banned?
if (BanLists.Enabled && BanLists.IsProfileBanned(client.Id)) {
// is the IPv4 address banned?
if (BanLists.Enabled && BanLists.IsIPv4Banned(((IPEndPoint) socket.RemoteEndPoint!).Address!)) {
Logger.Warn($"Ignoring banned IPv4 address for {client.Name} ({client.Id}/{remote})");
client.Ignored = true;
client.Logger.Warn($"Ignoring banned profile ID {client.Id}");
client.Banned = true;
}
// is the profile ID banned?
else if (BanLists.Enabled && BanLists.IsProfileBanned(client.Id)) {
client.Logger.Warn($"Ignoring banned profile ID for {client.Name} ({client.Id}/{remote})");
client.Ignored = true;
client.Banned = true;
}
// send server init (required to crash ignored players later)
await client.Send(new InitPacket {
MaxPlayers = (client.Ignored ? (ushort) 1 : Settings.Instance.Server.MaxPlayers),
});
// don't init or announce an ignored client to other players any further
if (client.Ignored) {
memory.Dispose();
continue;
}
// send server init
await client.Send(new InitPacket {
MaxPlayers = Settings.Instance.Server.MaxPlayers,
});
bool wasFirst = connect.ConnectionType == ConnectPacket.ConnectionTypes.FirstConnection;
// add client to the set of connected players