Skip to content

Commit 00c9c5e

Browse files
author
Matthew Bate
committed
Proxy Checks for TOR/VPN/Proxy and the need actions.
1 parent 9f7ab1c commit 00c9c5e

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed

BHD-ServerManager/Classes/Tickers/tickerBanManagement.cs

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ public static void runTicker()
152152
// Basic Ban Checks (Ignore Whitelist)
153153
CheckAndPuntBannedPlayers();
154154

155+
// Proxy/VPN/TOR and Geo-Blocking Checks
156+
CheckAndPuntProxyViolations();
157+
155158
}
156159
}
157160
else
@@ -744,5 +747,194 @@ private static string GetListStatus(string ipAddress, DateTime now)
744747

745748
return comments.Count > 0 ? string.Join(" | ", comments) : "OK";
746749
}
750+
751+
// Check active players against proxy/VPN/TOR rules and geo-blocking
752+
public static void CheckAndPuntProxyViolations()
753+
{
754+
// Only run if proxy checking is enabled
755+
if (!theInstance.proxyCheckEnabled)
756+
return;
757+
758+
DateTime now = DateTime.Now;
759+
760+
// Cycle through all players in the player list
761+
foreach (var kvp in theInstance.playerList)
762+
{
763+
int slotNum = kvp.Key;
764+
playerObject player = kvp.Value;
765+
766+
// Only check players who were seen in the last 4 seconds (active players)
767+
if ((now - player.PlayerLastSeen).TotalSeconds > 4)
768+
continue;
769+
770+
// Skip if player IP is not available
771+
if (string.IsNullOrEmpty(player.PlayerIPAddress))
772+
continue;
773+
774+
if (!IPAddress.TryParse(player.PlayerIPAddress, out IPAddress? playerIP))
775+
continue;
776+
777+
// Check if player is whitelisted (skip proxy checks for whitelisted players)
778+
bool isWhitelisted = false;
779+
780+
// Check name whitelist
781+
foreach (var whitelistedName in banInstance.WhitelistedNames)
782+
{
783+
if (whitelistedName.RecordType == banInstanceRecordType.Information)
784+
continue;
785+
786+
if (whitelistedName.RecordType == banInstanceRecordType.Temporary &&
787+
whitelistedName.ExpireDate.HasValue &&
788+
now > whitelistedName.ExpireDate.Value)
789+
continue;
790+
791+
if (player.PlayerName.Equals(whitelistedName.PlayerName, StringComparison.OrdinalIgnoreCase))
792+
{
793+
isWhitelisted = true;
794+
break;
795+
}
796+
}
797+
798+
// Check IP whitelist
799+
if (!isWhitelisted)
800+
{
801+
foreach (var whitelistedIP in banInstance.WhitelistedIPs)
802+
{
803+
if (whitelistedIP.RecordType == banInstanceRecordType.Information)
804+
continue;
805+
806+
if (whitelistedIP.RecordType == banInstanceRecordType.Temporary &&
807+
whitelistedIP.ExpireDate.HasValue &&
808+
now > whitelistedIP.ExpireDate.Value)
809+
continue;
810+
811+
if (IsIPMatch(playerIP, whitelistedIP.PlayerIP, whitelistedIP.SubnetMask))
812+
{
813+
isWhitelisted = true;
814+
break;
815+
}
816+
}
817+
}
818+
819+
// Skip whitelisted players
820+
if (isWhitelisted)
821+
continue;
822+
823+
// Find proxy record for this player's IP
824+
var proxyRecord = banInstance.ProxyRecords
825+
.FirstOrDefault(p => p.IPAddress.Equals(playerIP));
826+
827+
// If no proxy record exists or cache expired, trigger a check and skip for now
828+
if (proxyRecord == null || now > proxyRecord.CacheExpiry)
829+
{
830+
CheckIP(playerIP);
831+
continue;
832+
}
833+
834+
bool shouldPunt = false;
835+
bool shouldBan = false;
836+
string puntReason = string.Empty;
837+
838+
// Check Proxy
839+
if (proxyRecord.IsProxy && theInstance.proxyCheckProxyAction > 0)
840+
{
841+
shouldPunt = true;
842+
shouldBan = theInstance.proxyCheckProxyAction == 2;
843+
puntReason = $"Proxy detected{(shouldBan ? " (Auto-banned)" : " (Kicked)")}";
844+
AppDebug.Log("tickerBanManagement", $"Player '{player.PlayerName}' (Slot {slotNum}, IP: {player.PlayerIPAddress}) is using a PROXY. Action: {(shouldBan ? "Ban" : "Kick")}");
845+
}
846+
847+
// Check VPN
848+
if (!shouldPunt && proxyRecord.IsVpn && theInstance.proxyCheckVPNAction > 0)
849+
{
850+
shouldPunt = true;
851+
shouldBan = theInstance.proxyCheckVPNAction == 2;
852+
puntReason = $"VPN detected{(shouldBan ? " (Auto-banned)" : " (Kicked)")}";
853+
if (!string.IsNullOrEmpty(proxyRecord.Provider))
854+
puntReason += $" - {proxyRecord.Provider}";
855+
AppDebug.Log("tickerBanManagement", $"Player '{player.PlayerName}' (Slot {slotNum}, IP: {player.PlayerIPAddress}) is using a VPN. Action: {(shouldBan ? "Ban" : "Kick")}");
856+
}
857+
858+
// Check TOR
859+
if (!shouldPunt && proxyRecord.IsTor && theInstance.proxyCheckTORAction > 0)
860+
{
861+
shouldPunt = true;
862+
shouldBan = theInstance.proxyCheckTORAction == 2;
863+
puntReason = $"TOR detected{(shouldBan ? " (Auto-banned)" : " (Kicked)")}";
864+
AppDebug.Log("tickerBanManagement", $"Player '{player.PlayerName}' (Slot {slotNum}, IP: {player.PlayerIPAddress}) is using TOR. Action: {(shouldBan ? "Ban" : "Kick")}");
865+
}
866+
867+
// Check Geo-Blocking
868+
if (!shouldPunt && theInstance.proxyCheckGeoMode > 0 && !string.IsNullOrEmpty(proxyRecord.CountryCode))
869+
{
870+
bool countryInList = banInstance.ProxyBlockedCountries
871+
.Any(c => c.CountryCode.Equals(proxyRecord.CountryCode, StringComparison.OrdinalIgnoreCase));
872+
873+
// Mode 1 = Block listed countries
874+
// Mode 2 = Allow only listed countries
875+
bool shouldBlockCountry = theInstance.proxyCheckGeoMode == 1 ? countryInList : !countryInList;
876+
877+
if (shouldBlockCountry)
878+
{
879+
shouldPunt = true;
880+
shouldBan = false; // Geo-blocking only kicks, doesn't auto-ban
881+
var country = banInstance.ProxyBlockedCountries
882+
.FirstOrDefault(c => c.CountryCode.Equals(proxyRecord.CountryCode, StringComparison.OrdinalIgnoreCase));
883+
string countryName = country?.CountryName ?? proxyRecord.CountryCode;
884+
puntReason = $"Geo-blocked: {countryName} ({proxyRecord.CountryCode})";
885+
AppDebug.Log("tickerBanManagement", $"Player '{player.PlayerName}' (Slot {slotNum}, IP: {player.PlayerIPAddress}) from blocked country: {countryName}. Action: Kick");
886+
}
887+
}
888+
889+
// Execute action
890+
if (shouldPunt)
891+
{
892+
if (shouldBan)
893+
{
894+
// Create ban record
895+
var banRecord = new banInstancePlayerIP
896+
{
897+
RecordID = 0, // Will be set by database
898+
MatchID = theInstance.gameMatchID,
899+
PlayerIP = playerIP,
900+
SubnetMask = 32, // Exact IP match
901+
Date = now,
902+
ExpireDate = null, // Permanent ban
903+
AssociatedName = null,
904+
RecordType = banInstanceRecordType.Permanent,
905+
RecordCategory = 0, // Ban
906+
Notes = puntReason
907+
};
908+
909+
try
910+
{
911+
// Add to database
912+
int recordId = DatabaseManager.AddPlayerIPRecord(banRecord);
913+
banRecord.RecordID = recordId;
914+
915+
// Add to in-memory ban list
916+
banInstance.BannedPlayerIPs.Add(banRecord);
917+
918+
AppDebug.Log("tickerBanManagement", $"Auto-banned IP {player.PlayerIPAddress}: {puntReason}");
919+
920+
// Add to NetLimiter filter if enabled
921+
if (!string.IsNullOrEmpty(theInstance.netLimiterFilterName))
922+
{
923+
_ = NetLimiterClient.AddIpToFilterAsync(theInstance.netLimiterFilterName, player.PlayerIPAddress, 32);
924+
}
925+
}
926+
catch (Exception ex)
927+
{
928+
AppDebug.Log("tickerBanManagement", $"Error adding auto-ban record for IP {player.PlayerIPAddress}: {ex.Message}");
929+
}
930+
}
931+
932+
// Punt the player
933+
ServerMemory.WriteMemorySendConsoleCommand("punt " + slotNum);
934+
AppDebug.Log("tickerBanManagement", $"Punting player '{player.PlayerName}' (Slot {slotNum}). Reason: {puntReason}");
935+
}
936+
}
937+
}
938+
747939
}
748940
}

0 commit comments

Comments
 (0)