Skip to content

Commit 946d10b

Browse files
committed
Enhanced reporting DDoS & Web Attack
1 parent b977de7 commit 946d10b

File tree

5 files changed

+158
-19
lines changed

5 files changed

+158
-19
lines changed

Zolian.Server.Base/GameScripts/Skills/SharpShooterSkillTree.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,17 @@ protected override void OnSuccess(Sprite sprite)
145145

146146
Task.Run(async () =>
147147
{
148-
foreach (var i in enemy.Where(i => sprite.Serial != i.Serial))
148+
foreach (var i in enemy.Where(i => i != null && sprite.Serial != i.Serial))
149149
{
150-
if (!i.Alive) return;
150+
if (!i.Alive) continue;
151151
damageDealer.SendAnimationNearby(374, i.Position);
152152
}
153153

154154
await Task.Delay(5000);
155155

156-
foreach (var i in enemy.Where(i => sprite.Serial != i.Serial))
156+
foreach (var i in enemy.Where(i => i != null && sprite.Serial != i.Serial))
157157
{
158-
if (!i.Alive) return;
158+
if (!i.Alive) continue;
159159
var dmgCalc = DamageCalc(sprite, i);
160160

161161
if (sprite is Aisling aisling)

Zolian.Server.Base/Network/Server/BadActor.cs

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Net;
1+
using System.Collections.Concurrent;
2+
using System.Net;
23

34
using Darkages.Models;
45

@@ -12,10 +13,27 @@
1213

1314
namespace Darkages.Network.Server;
1415

16+
public class ReportInfo
17+
{
18+
public string RemoteIp { get; init; }
19+
public string Comment { get; init; }
20+
public DateTime FirstAttemptTime { get; init; }
21+
}
22+
1523
public static class BadActor
1624
{
25+
private static readonly ConcurrentQueue<ReportInfo> RetryQueue = [];
26+
private static bool _isProcessingQueue;
1727
private const string InternalIP = "192.168.50.1"; // Cannot use ServerConfig due to value needing to be constant
1828

29+
public static void StartProcessingQueue()
30+
{
31+
if (_isProcessingQueue) return;
32+
33+
_isProcessingQueue = true;
34+
Task.Run(ProcessRetryQueue);
35+
}
36+
1937
public static bool ClientOnBlackList(string remoteIp)
2038
{
2139
if (remoteIp.IsNullOrEmpty() || !IPAddress.TryParse(remoteIp, out _)) return true;
@@ -46,16 +64,17 @@ public static bool ClientOnBlackList(string remoteIp)
4664
var tor = ipdb?.Data?.IsTor;
4765
var usageType = ipdb?.Data?.UsageType;
4866

67+
// Block if using tor, potentially malicious
4968
if (tor == true)
5069
{
51-
LogBadActor(remoteIp, "using tor");
70+
LogBadActor(remoteIp, "using tor, potentially malicious");
5271
return true;
5372
}
5473

55-
// Block if known malicious usage type
56-
if (IsMaliciousUsageType(usageType))
74+
// Block if an unauthorized usage type
75+
if (IsBlockedUsageType(usageType))
5776
{
58-
LogBadActor(remoteIp, $"using {usageType}");
77+
LogBlockedType(remoteIp, $"using {usageType}");
5978
return true;
6079
}
6180

@@ -112,10 +131,16 @@ private static void LogBadActor(string remoteIp, string reason)
112131
{
113132
ServerSetup.ConnectionLogger($"Blocking {remoteIp} - Reason: {reason}", LogLevel.Warning);
114133
SentrySdk.CaptureMessage($"{remoteIp} blocked due to {reason}");
115-
ReportEndpoint(remoteIp, $"Blocked due to {reason}");
134+
ReportMaliciousEndpoint(remoteIp, $"Blocked due to {reason}");
116135
}
117136

118-
private static bool IsMaliciousUsageType(string usageType)
137+
private static void LogBlockedType(string remoteIp, string reason)
138+
{
139+
ServerSetup.ConnectionLogger($"Blocking {remoteIp} - Using: {reason}", LogLevel.Warning);
140+
ReportSuspiciousEndpoint(remoteIp, "Blocked due to Web Spam, Port Scanning");
141+
}
142+
143+
private static bool IsBlockedUsageType(string usageType)
119144
{
120145
return usageType switch
121146
{
@@ -124,7 +149,7 @@ private static bool IsMaliciousUsageType(string usageType)
124149
};
125150
}
126151

127-
public static void ReportEndpoint(string remoteIp, string comment)
152+
public static void ReportMaliciousEndpoint(string remoteIp, string comment)
128153
{
129154
var keyCode = ServerSetup.Instance.KeyCode;
130155
if (keyCode is null || keyCode.Length == 0)
@@ -147,10 +172,127 @@ public static void ReportEndpoint(string remoteIp, string comment)
147172
ServerSetup.ConnectionLogger($"Error reporting {remoteIp} : {comment}");
148173
SentrySdk.CaptureMessage($"Error reporting {remoteIp} : {comment}");
149174
}
175+
catch (HttpRequestException httpEx) when (httpEx.Message.Contains("TooManyRequests"))
176+
{
177+
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: Too many requests.", LogLevel.Warning);
178+
// add to queue where we report them also for DDoS (4)
179+
AddToRetryQueue(remoteIp, comment);
180+
}
150181
catch (Exception ex)
151182
{
152183
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: {ex.Message}", LogLevel.Warning);
153184
SentrySdk.CaptureException(ex);
154185
}
155186
}
187+
188+
private static void ReportSuspiciousEndpoint(string remoteIp, string comment)
189+
{
190+
var keyCode = ServerSetup.Instance.KeyCode;
191+
if (keyCode is null || keyCode.Length == 0)
192+
{
193+
ServerSetup.ConnectionLogger("Keycode not valid or not set within ServerConfig.json");
194+
return;
195+
}
196+
197+
try
198+
{
199+
var request = new RestRequest("", Method.Post);
200+
request.AddHeader("Key", keyCode);
201+
request.AddHeader("Accept", "application/json");
202+
request.AddParameter("ip", remoteIp);
203+
request.AddParameter("categories", "10, 14");
204+
request.AddParameter("comment", comment);
205+
var response = ExecuteWithRetry(() => ServerSetup.Instance.RestReport.Execute(request));
206+
207+
if (response.Result?.IsSuccessful == true) return;
208+
ServerSetup.ConnectionLogger($"Error reporting {remoteIp} : {comment}");
209+
SentrySdk.CaptureMessage($"Error reporting {remoteIp} : {comment}");
210+
}
211+
catch (HttpRequestException httpEx) when (httpEx.Message.Contains("TooManyRequests"))
212+
{
213+
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: Too many requests.", LogLevel.Warning);
214+
// add to queue where we report them also for DDoS (4)
215+
AddToRetryQueue(remoteIp, comment);
216+
}
217+
catch (Exception ex)
218+
{
219+
ServerSetup.ConnectionLogger($"Exception while reporting {remoteIp}: {ex.Message}", LogLevel.Warning);
220+
SentrySdk.CaptureException(ex);
221+
}
222+
}
223+
224+
private static void AddToRetryQueue(string remoteIp, string comment)
225+
{
226+
RetryQueue.Enqueue(new ReportInfo
227+
{
228+
RemoteIp = remoteIp,
229+
Comment = comment,
230+
FirstAttemptTime = DateTime.Now
231+
});
232+
}
233+
234+
private static async Task ProcessRetryQueue()
235+
{
236+
while (_isProcessingQueue)
237+
{
238+
if (!RetryQueue.IsEmpty)
239+
{
240+
// Process each report in the queue
241+
if (RetryQueue.TryDequeue(out var report))
242+
{
243+
var elapsedTime = DateTime.Now - report.FirstAttemptTime;
244+
245+
if (elapsedTime.TotalMinutes >= 1)
246+
{
247+
var success = await ReportSuspiciousEndpointWithDDoS(report);
248+
if (success)
249+
{
250+
ServerSetup.ConnectionLogger($"Successfully reported {report.RemoteIp} after retry.");
251+
}
252+
else
253+
{
254+
RetryQueue.Enqueue(report);
255+
ServerSetup.ConnectionLogger($"Retry failed for {report.RemoteIp}, re-queued.");
256+
}
257+
}
258+
else
259+
{
260+
await Task.Delay(TimeSpan.FromMinutes(1) - elapsedTime);
261+
RetryQueue.Enqueue(report);
262+
}
263+
}
264+
}
265+
266+
await Task.Delay(5000);
267+
}
268+
}
269+
270+
private static async Task<bool> ReportSuspiciousEndpointWithDDoS(ReportInfo report)
271+
{
272+
var adjustedComment = $"{report.Comment} - DDoS";
273+
274+
try
275+
{
276+
var keyCode = ServerSetup.Instance.KeyCode;
277+
if (string.IsNullOrEmpty(keyCode))
278+
{
279+
ServerSetup.ConnectionLogger("Keycode not valid or not set within ServerConfig.json");
280+
return false;
281+
}
282+
283+
var request = new RestRequest("", Method.Post);
284+
request.AddHeader("Key", keyCode);
285+
request.AddHeader("Accept", "application/json");
286+
request.AddParameter("ip", report.RemoteIp);
287+
request.AddParameter("categories", "4, 10, 14");
288+
request.AddParameter("comment", adjustedComment);
289+
290+
var response = await ServerSetup.Instance.RestReport.ExecuteAsync(request);
291+
return response.IsSuccessful;
292+
}
293+
catch
294+
{
295+
return false;
296+
}
297+
}
156298
}

Zolian.Server.Base/Network/Server/LoginServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ protected override void OnConnected(Socket clientSocket)
539539
ServerSetup.ConnectionLogger("---------Login-Server---------");
540540
var comment = $"{ipAddress} has been blocked for violating security protocols through improper port access.";
541541
ServerSetup.ConnectionLogger(comment, LogLevel.Warning);
542-
BadActor.ReportEndpoint(ipAddress.ToString(), comment);
542+
BadActor.ReportMaliciousEndpoint(ipAddress.ToString(), comment);
543543
return;
544544
}
545545

Zolian.Server.Base/Network/Server/ServerSetup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public ServerSetup(IOptions<ServerOptions> options)
103103
var restSettings = SetupRestClients();
104104
RestClient = new RestClient(restSettings.Item1);
105105
RestReport = new RestClient(restSettings.Item2);
106+
BadActor.StartProcessingQueue();
106107

107108
const string logTemplate = "[{Timestamp:MMM-dd HH:mm:ss} {Level:u3}] {Message}{NewLine}{Exception}";
108109
_packetLogger = new LoggerConfiguration()

Zolian.Server.Base/Network/Server/WorldServer.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,8 +1386,7 @@ private static async ValueTask LoadAislingAsync(IWorldClient client, IRedirect r
13861386
return;
13871387
}
13881388

1389-
client.SendServerMessage(ServerMessageType.ActiveMessage,
1390-
$"{ServerSetup.Instance.Config.ServerWelcomeMessage}: {client.Aisling.Username}");
1389+
client.SendServerMessage(ServerMessageType.ActiveMessage, $"{ServerSetup.Instance.Config.ServerWelcomeMessage}: {client.Aisling.Username}");
13911390
client.SendAttributes(StatUpdateType.Full);
13921391
client.LoggedIn(true);
13931392

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

14011400
if (client.Aisling.AreaId == ServerSetup.Instance.Config.TransitionZone)
1402-
{
1403-
var portal = new PortalSession();
14041401
PortalSession.TransitionToMap(client.Aisling.Client);
1405-
}
14061402
}
14071403
catch (Exception e)
14081404
{
@@ -3281,7 +3277,7 @@ protected override void OnConnected(Socket clientSocket)
32813277
ServerSetup.ConnectionLogger("---------World-Server---------");
32823278
var comment = $"{ipAddress} has been blocked for violating security protocols through improper port access.";
32833279
ServerSetup.ConnectionLogger(comment, LogLevel.Warning);
3284-
BadActor.ReportEndpoint(ipAddress.ToString(), comment);
3280+
BadActor.ReportMaliciousEndpoint(ipAddress.ToString(), comment);
32853281
return;
32863282
}
32873283

0 commit comments

Comments
 (0)