Skip to content

Commit

Permalink
Enhanced reporting DDoS & Web Attack
Browse files Browse the repository at this point in the history
  • Loading branch information
FallenDev committed Jan 4, 2025
1 parent b977de7 commit 946d10b
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,17 @@ protected override void OnSuccess(Sprite sprite)

Task.Run(async () =>
{
foreach (var i in enemy.Where(i => sprite.Serial != i.Serial))
foreach (var i in enemy.Where(i => i != null && sprite.Serial != i.Serial))
{
if (!i.Alive) return;
if (!i.Alive) continue;
damageDealer.SendAnimationNearby(374, i.Position);
}

await Task.Delay(5000);

foreach (var i in enemy.Where(i => sprite.Serial != i.Serial))
foreach (var i in enemy.Where(i => i != null && sprite.Serial != i.Serial))
{
if (!i.Alive) return;
if (!i.Alive) continue;
var dmgCalc = DamageCalc(sprite, i);

if (sprite is Aisling aisling)
Expand Down
158 changes: 150 additions & 8 deletions Zolian.Server.Base/Network/Server/BadActor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net;
using System.Collections.Concurrent;
using System.Net;

using Darkages.Models;

Expand All @@ -12,10 +13,27 @@

namespace Darkages.Network.Server;

public class ReportInfo
{
public string RemoteIp { get; init; }
public string Comment { get; init; }
public DateTime FirstAttemptTime { get; init; }
}

public static class BadActor
{
private static readonly ConcurrentQueue<ReportInfo> RetryQueue = [];
private static bool _isProcessingQueue;
private const string InternalIP = "192.168.50.1"; // Cannot use ServerConfig due to value needing to be constant

public static void StartProcessingQueue()
{
if (_isProcessingQueue) return;

_isProcessingQueue = true;
Task.Run(ProcessRetryQueue);
}

public static bool ClientOnBlackList(string remoteIp)
{
if (remoteIp.IsNullOrEmpty() || !IPAddress.TryParse(remoteIp, out _)) return true;
Expand Down Expand Up @@ -46,16 +64,17 @@ public static bool ClientOnBlackList(string remoteIp)
var tor = ipdb?.Data?.IsTor;
var usageType = ipdb?.Data?.UsageType;

// Block if using tor, potentially malicious
if (tor == true)
{
LogBadActor(remoteIp, "using tor");
LogBadActor(remoteIp, "using tor, potentially malicious");
return true;
}

// Block if known malicious usage type
if (IsMaliciousUsageType(usageType))
// Block if an unauthorized usage type
if (IsBlockedUsageType(usageType))
{
LogBadActor(remoteIp, $"using {usageType}");
LogBlockedType(remoteIp, $"using {usageType}");
return true;
}

Expand Down Expand Up @@ -112,10 +131,16 @@ private static void LogBadActor(string remoteIp, string reason)
{
ServerSetup.ConnectionLogger($"Blocking {remoteIp} - Reason: {reason}", LogLevel.Warning);
SentrySdk.CaptureMessage($"{remoteIp} blocked due to {reason}");
ReportEndpoint(remoteIp, $"Blocked due to {reason}");
ReportMaliciousEndpoint(remoteIp, $"Blocked due to {reason}");
}

private static bool IsMaliciousUsageType(string usageType)
private static void LogBlockedType(string remoteIp, string reason)
{
ServerSetup.ConnectionLogger($"Blocking {remoteIp} - Using: {reason}", LogLevel.Warning);
ReportSuspiciousEndpoint(remoteIp, "Blocked due to Web Spam, Port Scanning");
}

private static bool IsBlockedUsageType(string usageType)
{
return usageType switch
{
Expand All @@ -124,7 +149,7 @@ private static bool IsMaliciousUsageType(string usageType)
};
}

public static void ReportEndpoint(string remoteIp, string comment)
public static void ReportMaliciousEndpoint(string remoteIp, string comment)
{
var keyCode = ServerSetup.Instance.KeyCode;
if (keyCode is null || keyCode.Length == 0)
Expand All @@ -147,10 +172,127 @@ public static void ReportEndpoint(string remoteIp, string comment)
ServerSetup.ConnectionLogger($"Error reporting {remoteIp} : {comment}");
SentrySdk.CaptureMessage($"Error reporting {remoteIp} : {comment}");
}
catch (HttpRequestException httpEx) when (httpEx.Message.Contains("TooManyRequests"))
{
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: Too many requests.", LogLevel.Warning);
// add to queue where we report them also for DDoS (4)
AddToRetryQueue(remoteIp, comment);
}
catch (Exception ex)
{
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: {ex.Message}", LogLevel.Warning);
SentrySdk.CaptureException(ex);
}
}

private static void ReportSuspiciousEndpoint(string remoteIp, string comment)
{
var keyCode = ServerSetup.Instance.KeyCode;
if (keyCode is null || keyCode.Length == 0)
{
ServerSetup.ConnectionLogger("Keycode not valid or not set within ServerConfig.json");
return;
}

try
{
var request = new RestRequest("", Method.Post);
request.AddHeader("Key", keyCode);
request.AddHeader("Accept", "application/json");
request.AddParameter("ip", remoteIp);
request.AddParameter("categories", "10, 14");
request.AddParameter("comment", comment);
var response = ExecuteWithRetry(() => ServerSetup.Instance.RestReport.Execute(request));

if (response.Result?.IsSuccessful == true) return;
ServerSetup.ConnectionLogger($"Error reporting {remoteIp} : {comment}");
SentrySdk.CaptureMessage($"Error reporting {remoteIp} : {comment}");
}
catch (HttpRequestException httpEx) when (httpEx.Message.Contains("TooManyRequests"))
{
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: Too many requests.", LogLevel.Warning);
// add to queue where we report them also for DDoS (4)
AddToRetryQueue(remoteIp, comment);
}
catch (Exception ex)
{
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: {ex.Message}", LogLevel.Warning);
SentrySdk.CaptureException(ex);
}
}

private static void AddToRetryQueue(string remoteIp, string comment)
{
RetryQueue.Enqueue(new ReportInfo
{
RemoteIp = remoteIp,
Comment = comment,
FirstAttemptTime = DateTime.Now
});
}

private static async Task ProcessRetryQueue()
{
while (_isProcessingQueue)
{
if (!RetryQueue.IsEmpty)
{
// Process each report in the queue
if (RetryQueue.TryDequeue(out var report))
{
var elapsedTime = DateTime.Now - report.FirstAttemptTime;

if (elapsedTime.TotalMinutes >= 1)
{
var success = await ReportSuspiciousEndpointWithDDoS(report);
if (success)
{
ServerSetup.ConnectionLogger($"Successfully reported {report.RemoteIp} after retry.");
}
else
{
RetryQueue.Enqueue(report);
ServerSetup.ConnectionLogger($"Retry failed for {report.RemoteIp}, re-queued.");
}
}
else
{
await Task.Delay(TimeSpan.FromMinutes(1) - elapsedTime);
RetryQueue.Enqueue(report);
}
}
}

await Task.Delay(5000);
}
}

private static async Task<bool> ReportSuspiciousEndpointWithDDoS(ReportInfo report)
{
var adjustedComment = $"{report.Comment} - DDoS";

try
{
var keyCode = ServerSetup.Instance.KeyCode;
if (string.IsNullOrEmpty(keyCode))
{
ServerSetup.ConnectionLogger("Keycode not valid or not set within ServerConfig.json");
return false;
}

var request = new RestRequest("", Method.Post);
request.AddHeader("Key", keyCode);
request.AddHeader("Accept", "application/json");
request.AddParameter("ip", report.RemoteIp);
request.AddParameter("categories", "4, 10, 14");
request.AddParameter("comment", adjustedComment);

var response = await ServerSetup.Instance.RestReport.ExecuteAsync(request);
return response.IsSuccessful;
}
catch
{
return false;
}
}
}
2 changes: 1 addition & 1 deletion Zolian.Server.Base/Network/Server/LoginServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ protected override void OnConnected(Socket clientSocket)
ServerSetup.ConnectionLogger("---------Login-Server---------");
var comment = $"{ipAddress} has been blocked for violating security protocols through improper port access.";
ServerSetup.ConnectionLogger(comment, LogLevel.Warning);
BadActor.ReportEndpoint(ipAddress.ToString(), comment);
BadActor.ReportMaliciousEndpoint(ipAddress.ToString(), comment);
return;
}

Expand Down
1 change: 1 addition & 0 deletions Zolian.Server.Base/Network/Server/ServerSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public ServerSetup(IOptions<ServerOptions> options)
var restSettings = SetupRestClients();
RestClient = new RestClient(restSettings.Item1);
RestReport = new RestClient(restSettings.Item2);
BadActor.StartProcessingQueue();

const string logTemplate = "[{Timestamp:MMM-dd HH:mm:ss} {Level:u3}] {Message}{NewLine}{Exception}";
_packetLogger = new LoggerConfiguration()
Expand Down
8 changes: 2 additions & 6 deletions Zolian.Server.Base/Network/Server/WorldServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,8 +1386,7 @@ private static async ValueTask LoadAislingAsync(IWorldClient client, IRedirect r
return;
}

client.SendServerMessage(ServerMessageType.ActiveMessage,
$"{ServerSetup.Instance.Config.ServerWelcomeMessage}: {client.Aisling.Username}");
client.SendServerMessage(ServerMessageType.ActiveMessage, $"{ServerSetup.Instance.Config.ServerWelcomeMessage}: {client.Aisling.Username}");
client.SendAttributes(StatUpdateType.Full);
client.LoggedIn(true);

Expand All @@ -1399,10 +1398,7 @@ private static async ValueTask LoadAislingAsync(IWorldClient client, IRedirect r
}

if (client.Aisling.AreaId == ServerSetup.Instance.Config.TransitionZone)
{
var portal = new PortalSession();
PortalSession.TransitionToMap(client.Aisling.Client);
}
}
catch (Exception e)
{
Expand Down Expand Up @@ -3281,7 +3277,7 @@ protected override void OnConnected(Socket clientSocket)
ServerSetup.ConnectionLogger("---------World-Server---------");
var comment = $"{ipAddress} has been blocked for violating security protocols through improper port access.";
ServerSetup.ConnectionLogger(comment, LogLevel.Warning);
BadActor.ReportEndpoint(ipAddress.ToString(), comment);
BadActor.ReportMaliciousEndpoint(ipAddress.ToString(), comment);
return;
}

Expand Down

0 comments on commit 946d10b

Please sign in to comment.