Skip to content

Commit 79a0c30

Browse files
committed
Hide ghost lobbies after a while, add IP ban, fixes for healthcheck script
1 parent 2c71291 commit 79a0c30

13 files changed

Lines changed: 250 additions & 79 deletions

File tree

LdnServer/HostedGame.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ public NetworkInfo Info
6565
}
6666

6767
public string Id { get; }
68+
public long CreatedAt { get; }
6869

6970
public bool Closing { get; set; }
7071

@@ -123,6 +124,7 @@ private set
123124
public HostedGame(string id, NetworkInfo info, AddressList dhcpConfig)
124125
{
125126
Id = id;
127+
CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
126128

127129
_lock = new object();
128130
_players = new List<LdnSession>();

LdnServer/IPBan.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Net;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace LanPlayServer
11+
{
12+
internal static class IPBan
13+
{
14+
private static ConcurrentBag<string> _bannedIPs;
15+
private static object _lock = new object();
16+
private static string _banFilePath = Environment.GetEnvironmentVariable("IP_BAN_FILE_PATH") ?? "bannedips.txt";
17+
18+
static IPBan()
19+
{
20+
_bannedIPs = new ConcurrentBag<string>();
21+
if (!File.Exists(_banFilePath))
22+
{
23+
File.Create(_banFilePath).Close();
24+
}
25+
else
26+
{
27+
string[] lines = File.ReadAllLines(_banFilePath);
28+
foreach (string line in lines)
29+
{
30+
_bannedIPs.Add(line);
31+
}
32+
}
33+
}
34+
35+
public static void BanIP(IPAddress ip)
36+
{
37+
try
38+
{
39+
string ipString = ip.ToString();
40+
lock (_lock)
41+
{
42+
if (!_bannedIPs.Contains(ipString))
43+
{
44+
_bannedIPs.Add(ipString);
45+
File.AppendAllText(_banFilePath, ipString + Environment.NewLine);
46+
}
47+
}
48+
}
49+
catch (Exception e)
50+
{
51+
Console.WriteLine($"Failed to ban IP {ip}: {e.Message}");
52+
}
53+
}
54+
55+
public static bool IsIPBanned(IPAddress ip)
56+
{
57+
return _bannedIPs.Contains(ip.ToString());
58+
}
59+
60+
public static List<string> GetBannedIPs()
61+
{
62+
return _bannedIPs.ToList();
63+
}
64+
}
65+
}

LdnServer/LdnServer.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ public int Scan(ref NetworkInfo[] info, ScanFilter filter, string passphrase, Ho
9090
int gameCount = all.Length;
9191
int playerCount = 0;
9292

93+
long currentTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
94+
long oneHour = 3600000;
95+
// Games older than this are probably bugged "ghost" lobbies, still rarely happens, there's probably still a lock issue somewhere
96+
long minTime = currentTime - (oneHour * 16);
97+
9398
for (int i = 0; i < all.Length; i++)
9499
{
95100
HostedGame game = all[i].Value;
@@ -104,6 +109,11 @@ public int Scan(ref NetworkInfo[] info, ScanFilter filter, string passphrase, Ho
104109
continue;
105110
}
106111

112+
if (game.CreatedAt < minTime)
113+
{
114+
continue;
115+
}
116+
107117
NetworkInfo scanInfo = game.Info;
108118

109119
if (scanInfo.Ldn.StationAcceptPolicy == 1)

LdnServer/LdnSession.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ protected override void OnConnected()
212212
try
213213
{
214214
RealIpAddress = GetSessionIp();
215+
var ipToCheck = ((IPEndPoint)Socket.RemoteEndPoint).Address;
216+
if (IPBan.IsIPBanned(ipToCheck))
217+
{
218+
Console.WriteLine($"Banned IP tried to connect: {ipToCheck}");
219+
Disconnect();
220+
return;
221+
}
215222
}
216223
catch
217224
{
@@ -317,6 +324,16 @@ private void HandleScan(LdnHeader ldnPacket, ScanFilter filter)
317324

318325
private void HandleCreateAccessPoint(LdnHeader ldnPacket, CreateAccessPointRequest request, byte[] advertiseData)
319326
{
327+
var nameAsString = StringUtils.ReadUtf8String(request.UserConfig.UserName.AsSpan());
328+
if (nameAsString.ContainsSlur())
329+
{
330+
var ipToBan = ((IPEndPoint)Socket.RemoteEndPoint).Address;
331+
Console.WriteLine($"Banning {nameAsString} ({ipToBan})");
332+
IPBan.BanIP(ipToBan);
333+
SendAsync(RyuLdnProtocol.Encode(PacketId.NetworkError, new NetworkErrorMessage { Error = NetworkError.BannedByServer }));
334+
Disconnect();
335+
return;
336+
}
320337
if (CurrentGame != null || !_initialized)
321338
{
322339
// Cannot create an access point while in a game.
@@ -487,6 +504,17 @@ private bool IsProxyReachable(ushort port)
487504

488505
private void ConnectImpl(string id, UserConfig userConfig, uint localCommunicationVersion)
489506
{
507+
var nameAsString = StringUtils.ReadUtf8String(userConfig.UserName.AsSpan());
508+
if (nameAsString.ContainsSlur())
509+
{
510+
var ipToBan = ((IPEndPoint)Socket.RemoteEndPoint).Address;
511+
Console.WriteLine($"Banning {nameAsString} ({ipToBan})");
512+
IPBan.BanIP(ipToBan);
513+
SendAsync(RyuLdnProtocol.Encode(PacketId.NetworkError, new NetworkErrorMessage { Error = NetworkError.BannedByServer }));
514+
Disconnect();
515+
return;
516+
}
517+
490518
HostedGame game = _tcpServer.FindGame(id);
491519

492520
if (game != null)

Network/Types/NetworkErrorMessage.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ public enum NetworkError : int
1919

2020
RejectFailed,
2121

22+
BannedByServer = 127,
23+
2224
Unknown = -1
2325
}
2426

Program.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ static void Main()
4646
GameList.Initialize(File.ReadAllText(GamelistPath));
4747
Console.WriteLine(" Done!");
4848

49-
_ldnServer = new(Host, Port);
49+
_ldnServer = new(Host, Port);
50+
51+
var bannedIPs = IPBan.GetBannedIPs();
52+
53+
Console.WriteLine($"Loaded {bannedIPs.Count} banned IPs");
5054

5155
Console.Write($"\tLdnServer (port: {Port}) starting...");
5256
_ldnServer.Start();

Stats/Types/GameAnalytics.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public class GameAnalytics: INotifyPropertyChanged
2424
private string _status;
2525
private int _sceneId;
2626
private List<string> _players;
27+
private long _createdAt;
2728

2829
public string Id
2930
{
@@ -168,6 +169,19 @@ public List<string> Players
168169
}
169170
}
170171

172+
public long CreatedAt
173+
{
174+
get => _createdAt;
175+
set
176+
{
177+
if (_createdAt != value)
178+
{
179+
_createdAt = value;
180+
NotifyPropertyChanged();
181+
}
182+
}
183+
}
184+
171185
private static void FromGame(GameAnalytics instance, HostedGame game)
172186
{
173187
if (game.Closing)
@@ -202,6 +216,7 @@ private static void FromGame(GameAnalytics instance, HostedGame game)
202216
instance.Status = game.Info.Ldn.StationAcceptPolicy == 1 ? "Not Joinable" : "Joinable";
203217
instance.SceneId = game.Info.NetworkId.IntentId.SceneId;
204218
instance.Players = players;
219+
instance.CreatedAt = game.CreatedAt;
205220
}
206221

207222
public void Update(HostedGame game)

Utils/StringUtils.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ public static string ReadUtf8String(Span<byte> data, int index = 0)
7777
"\u0046\u0041\u0047\u0047\u004F\u0054"
7878
];
7979

80+
public static bool ContainsSlur(this string input)
81+
{
82+
foreach (var word in filterSlurs)
83+
{
84+
if (input.ToUpper().Contains(word))
85+
{
86+
return true;
87+
}
88+
}
89+
return false;
90+
}
91+
8092
public static string CleanInput(this string input, int maxLength = -1, string extraAllowedChars = "")
8193
{
8294
if (input == null)

Utils/gamelist.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8861,7 +8861,7 @@
88618861
},
88628862
{
88638863
"id": "0x0100ABF008968000",
8864-
"name": "Pokémon™ Sword"
8864+
"name": "Pokémon™ Sword/Shield"
88658865
},
88668866
{
88678867
"id": "0x0100AC3011C4C000",

docker-compose.yml

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ services:
1515
LDN_PORT: 30456
1616
LDN_REDIS_HOST: redis
1717
LDN_REDIS_PORT: 6379
18+
IP_BAN_FILE_PATH: /data/ryuldn/bannedips.txt
19+
volumes:
20+
- /data/ryuldn:/data/ryuldn
1821
ports:
1922
- "30456:30456"
2023
networks:
@@ -34,19 +37,6 @@ services:
3437
networks:
3538
- main
3639

37-
ryujinx-ldn-website2:
38-
# NOTE: Make sure the website repo is cloned to this location and up to date
39-
hostname: ryujinx-ldn-website2
40-
build: ../ryujinx-ldn-website2/
41-
environment:
42-
HOST: 0.0.0.0
43-
PORT: 8080
44-
REDIS_URL: "redis:6379"
45-
#ports:
46-
# - "8080:8081"
47-
networks:
48-
- main
49-
5040
networks:
5141
main:
5242
name: main

0 commit comments

Comments
 (0)