This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 8064ba84d8
commit 6a58f406b1
7522 changed files with 4011896 additions and 15 deletions

View File

@@ -0,0 +1,137 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if (SERVER) then
util.AddNetworkString("ixBindGrab")
util.AddNetworkString("ixBindGrabList")
end
CAMI.RegisterPrivilege({
Name = "Helix - Check Bind",
MinAccess = "superadmin"
})
ix.command.Add("PlyGetBinds", {
description = "Get a list of all of someone's binds.",
privilege = "Check Bind",
arguments = {ix.type.player, bit.bor(ix.type.optional, ix.type.bool)},
OnRun = function(self, client, target, all)
if (IsValid(target.ixBindGrab) and target.ixBindGrabTime and target.ixBindGrabTime > CurTime()) then
return "Someone else is checking this player's binds already. Please wait a few seconds!"
end
target.ixBindGrab = client
target.ixBindGrabTime = CurTime() + 5
target.ixBindGrabAll = all
net.Start("ixBindGrab")
net.Send(target)
end,
bNoIndicator = true
})
if (CLIENT) then
net.Receive("ixBindGrab", function()
net.Start("ixBindGrab")
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(input.LookupKeyBinding(i) or "", 255))
end
net.SendToServer()
end)
local blacklist = {
["slot0"] = true,
["slot1"] = true,
["slot2"] = true,
["slot3"] = true,
["slot4"] = true,
["slot5"] = true,
["slot6"] = true,
["slot7"] = true,
["slot8"] = true,
["slot9"] = true,
["+zoom"] = true,
["+forward"] = true,
["+back"] = true,
["+moveleft"] = true,
["+moveright"] = true,
["+jump"] = true,
["+speed"] = true,
["+walk"] = true,
["+duck"] = true,
["+lookup"] = true,
["+left"] = true,
["+lookdown"] = true,
["+right"] = true,
["+attack"] = true,
["+attack2"] = true,
["+reload"] = true,
["+use"] = true,
["invprev"] = true,
["invnext"] = true,
["+menu"] = true,
["+menu_context"] = true,
["gmod_undo"] = true,
["+showscores"] = true,
["gm_showhelp"] = true,
["gm_showteam"] = true,
["gm_showspare1"] = true,
["gm_showspare2"] = true,
["noclip"] = true,
["messagemode"] = true,
["toggleconsole"] = true,
["cancelselect"] = true,
["pause"] = true,
["save quick"] = true,
["load quick"] = true,
["impulse 100"] = true,
["+voicerecord"] = true,
["jpeg"] = true,
}
net.Receive("ixBindGrabList", function()
local all = net.ReadBool()
MsgN(net.ReadString().."'s binds ("..net.ReadString()..")")
for i = 1, BUTTON_CODE_LAST do
local bind = net.ReadString()
if (!all and blacklist[bind]) then continue end
if (bind and bind != "") then
if (#bind == 255) then
bind = bind.."..."
end
MsgN((input.GetKeyName(i) or i)..": ", bind)
end
end
LocalPlayer():Notify("Bindlar konsola yazdırıldı!")
end)
else
net.Receive("ixBindGrab", function(len, client)
if (!IsValid(client.ixBindGrab) or !CAMI.PlayerHasAccess(client.ixBindGrab, "Helix - Check Bind")) then return end
net.Start("ixBindGrabList")
net.WriteBool(client.ixBindGrabAll)
net.WriteString(client:SteamName())
net.WriteString(client:SteamID())
for i = 1, BUTTON_CODE_LAST do
net.WriteString(string.Left(net.ReadString(), 255))
end
net.Send(client.ixBindGrab)
client.ixBindGrab = nil
end)
end

View File

@@ -0,0 +1,507 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local pcall = pcall
local util = util
local ix = ix
local string = string
local net = net
local ipairs = ipairs
local IsValid = IsValid
local os = os
local L = L
local math = math
local table = table
local pairs = pairs
local print = print
local CHTTP = CHTTP
local player = player
local CAMI = CAMI
if (!CHTTP) then
pcall(require, "chttp")
end
local PLUGIN = PLUGIN
PLUGIN.TYPE_UNKNOWN = 1
PLUGIN.TYPE_KNOWN = 2
local COOKIE_KEY = "qvFT4QSSST8K4tZF"
local fileChecks = {
{"hl2_misc_001.vpk", "hl2"},
{"ep2_pak_008.vpk", "ep2"},
{"cstrike_pak_003.vpk", "css", "cstrike"},
{"bin/client_panorama.dll", "csgo"},
{"detail.vbsp", "gmod", "garrysmod"}
}
util.AddNetworkString("RecieveDupe")
ix.util.Include("sv_antialt_db.lua")
ix.lang.AddTable("english", {
altSignupProxy = "You are trying to join Willard Networks Turkiye as a new user while using a proxy or VPN. To combat alt accounts, we do not allow this.\n\nPlease turn off your proxy/VPN and rejoin the server. After you successfully joined the server once, you can turn on your proxy/VPN again for future visits.\n\nIf you are not using a proxy or VPN, please contact the community management on our forums or discord"
})
ix.log.AddType("altNewClient", function(client)
return string.format("[AltChecker] %s joined for the first time, generating new cookie.", client:SteamName())
end)
ix.log.AddType("altKnownNewCookie", function(client)
return string.format("[AltChecker] %s joined with unknown installation, generating new cookie.", client:SteamName())
end)
ix.log.AddType("altKnownCookieMatched", function(client, matched, total)
return string.format("[AltChecker] %s joined without a cookie, but matched installation with existing cookie. Certainty %d/%d", client:SteamName(), matched, total)
end)
hook.Add("PlayerInitialSpawn", "bastionAntiAlt", function(client)
if (client:IsBot()) then return end
client.ixAltData = {
checks = 4 + #fileChecks,
altLogging = 0,
error = false,
received = false,
checkComplete = false,
newAltFound = false,
mode = 0,
localCookie = "",
cookies = false,
ip = false,
timestamps = false,
otherCookies = {},
otherIPs = {},
otherTimestamps = {},
otherTimestampsNZ = {},
otherTimeMatches = {},
discordAlert = {
cookies = {},
timestamps = {},
ips = {},
altIDs = {}
}
}
-- Lookup user data
PLUGIN:AltLoadUserData(client)
if (PLUGIN.API_KEY) then
-- Lookup user IP
PLUGIN:AltLookupIP(client)
else
client.ixAltData.checkes = client.ixAltData.checks - 1
end
-- Check for IP matches
PLUGIN:AltLookupIPMatches(client)
-- Request cookie and install timestamps
PLUGIN:RequestClientData(client)
end)
function PLUGIN:RequestClientData(client)
net.Start("RecieveDupe")
net.WriteUInt(1, 3)
net.WriteString(COOKIE_KEY)
for _, v in ipairs(fileChecks) do
net.WriteString(v[1])
net.WriteString(v[3] or v[2])
end
net.Send(client)
end
net.Receive("RecieveDupe", function(len, client)
if (!IsValid(client) or !client.ixAltData or client.ixAltData.received) then return end
local data = client.ixAltData
data.received = true
-- set cookie
data.localCookie = net.ReadString()
-- set file timestamps
data.timestamps = {}
for i = 1, #fileChecks do
data.timestamps[i] = net.ReadUInt(32)
end
-- Check for cookie matches
if (data.localCookie != "") then
PLUGIN:AltLookupCookieMatches(client, data)
else
PLUGIN:AltPreFinalChecking(client)
end
-- Check for install timestamp matches
data.otherTimestamps = {}
data.otherTimestampsNZ = {}
for i = 1, #fileChecks do
PLUGIN:AltLookupTimestampMatches(client, data, fileChecks[i][2], data.timestamps[i])
end
end)
function PLUGIN:AltPreFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
-- if we errored, don't do anything
-- check will be reexecuted when the client rejoins
if (data.error) then return end
-- check if all queries finished
data.checks = data.checks - 1
if (data.checks != 0) then return end
-- cookie matches (STRONG)
if (#data.otherCookies > 0) then
for _, v in ipairs(data.otherCookies) do
self:AltFound(client, v[2], "cookie", "cookie")
data.discordAlert.cookies[#data.discordAlert.cookies + 1] = (v[2] or "").." ("..(v[1] or "")..")"
data.discordAlert.altIDs[v[2]] = true
end
end
-- IP (WEAK)
if (#data.otherIPs > 0) then
for _, v in ipairs(data.otherIPs) do
data.discordAlert.ips[#data.discordAlert.ips + 1] = v[2]
data.discordAlert.altIDs[v[2]] = true
end
end
-- time matches (STRONG-MEDIUM)
self:AggregateTimestampMatches(data)
-- If no local cookie and player is known, check if a known cookie was time-matched
if (data.localCookie == "" and data.mode == self.TYPE_KNOWN) then
self:FindMatchingCookie(client, data)
end
if (#data.otherTimeMatches > 0) then
-- go looking for the other clients that own our matched timestamps
self:AltLookupCookieForTimestamps(client, data, #fileChecks)
else
-- else we don't need to wait for the lookup above
data.checkComplete = true
self:AltFinalChecking(client)
end
end
function PLUGIN:AltFinalChecking(client)
if (!IsValid(client)) then return end
local data = client.ixAltData
if (!data.checkComplete or data.altLogging != 0) then return end
self:DiscordAlert(client)
-- update IP list
local steamID = client:SteamID64()
local ip = self.GetIPAddress(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("steamid", steamID)
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0) then
local query2 = mysql:Insert("bastion_antialt_userips")
query2:Insert("steamid", steamID)
query2:Insert("ip", ip)
query2:Insert("last_seen", os.time())
query2:Execute()
else
local query2 = mysql:Update("bastion_antialt_userips")
query2:Where("id", result[1].id)
query2:Update("last_seen", os.time())
query2:Execute()
end
end)
query:Execute()
-- Kick if new player on proxy/vpn
if (data.mode == self.TYPE_UNKNOWN) then
if (self.API_KEY and (data.ip.proxy == "yes" or (data.ip.risk or 0) > 60)) then
if (ix.config.Get("VPNKick")) then
self:ProxyAlert(client)
client:Kick(L("altSignupProxy", client))
else
if (!self:NotifyProxyJoin(client) or ix.config.Get("ProxyAlwaysAlert")) then
self:ProxyAlert(client)
end
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
elseif (data.localCookie == "") then
ix.log.Add(client, "altKnownNewCookie")
self:GenerateCookie(client, data)
else
-- Update the cookie's timestamps
self:StoreCookieInfo(data, fileChecks)
-- Add this cookie to client as well so it can be time matched/timestamps updated
self:StoreClientCookie(client, data)
end
if (sam) then
timer.Simple(3, function()
if (!IsValid(client)) then return end
local query1 = mysql:Select("bastion_antialt_alts")
query1:Where("steamid", client:SteamID64())
query1:Select("alt_id")
query1:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then return end
local query2 = mysql:Select("bastion_antialt_alts")
query2:Where("alt_id", result[1].alt_id)
query2:WhereNotEqual("steamid", client:SteamID64())
query2:Select("steamid")
query2:Callback(function(result2)
if (!IsValid(client)) then return end
if (!result2 or #result2 == 0) then return end
for k, v in ipairs(result2) do
sam.player.is_banned(util.SteamIDFrom64(v.steamid), function(banned)
if (!banned or !IsValid(client)) then return end
client:Kick("You have a banned alt account.")
return
end)
end
end)
query2:Execute()
end)
query1:Execute()
end)
end
end
--[[
COOKIE STUFF
]]
function PLUGIN:WhitelistPlayer(client)
local data = client.ixAltData
if (!data) then return end
if (data.localCookie) then
ix.log.Add(client, "altNewClient")
self:GenerateCookie(client, data)
return true
end
end
function PLUGIN.RandomString()
local result = {} -- The empty table we start with
while (#result != 64) do
local char = string.char(math.random(32, 126))
if (string.find(char, "%w")) then
result[#result + 1] = char
end
end
return table.concat(result)
end
function PLUGIN:GenerateCookie(client, data)
local cookie = self.RandomString()
self:UpdateLocalCookie(client, data, cookie)
local query = mysql:Insert("bastion_antialt_users")
query:Insert("steamid", client:SteamID64())
query:Insert("steam_name", client:SteamName())
query:Insert("cookie", cookie)
query:Execute()
end
function PLUGIN:UpdateLocalCookie(client, data, cookie)
data.localCookie = cookie
net.Start("RecieveDupe")
net.WriteUInt(2, 3)
net.WriteString(COOKIE_KEY)
net.WriteString(cookie)
net.Send(client)
self:StoreCookieInfo(data, fileChecks)
end
function PLUGIN:FindMatchingCookie(client, data)
for _, v in ipairs(data.otherTimeMatches) do
for _, v1 in ipairs(data.cookies) do
if (v1.cookie == v[1]) then
-- found a timestamp match belonging to the client, restore cookie
-- in case of e.g. gmod reinstall
ix.log.Add(client, "altKnownCookieMatched", v[2], #fileChecks)
self:UpdateLocalCookie(client, data, v[1])
return
end
end
end
end
--[[
LOGGING AND ALERTING
]]
local ALT_OFFSET = 0
function PLUGIN:AltFound(client, steamid, type, info)
local ids = {client:SteamID64(), steamid}
local data = client.ixAltData
data.altLogging = data.altLogging + 1
local query = mysql:Select("bastion_antialt_alts")
query:WhereIn("steamid", ids)
query:Callback(function(result)
if (!result or #result == 0) then
local alt_id = os.time() + ALT_OFFSET
ALT_OFFSET = ALT_OFFSET + 1
local text = table.concat(ids,"+")..": "..info.." (alt-id: "..alt_id..")"
self:InsertNewAlt(ids[1], alt_id, type, text)
self:InsertNewAlt(steamid, alt_id, type, text)
data.newAltFound = true
elseif (#result == 1) then
self:InsertNewAlt(
result[1].steamid == steamid and ids[1] or steamid,
result[1].alt_id,
type,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
elseif (result[2].alt_id != result[1].alt_id) then
self:MergeAlts(
result[2].alt_id,
result[1].alt_id,
table.concat(ids,"+")..": "..info.." (alt-id: "..result[1].alt_id..")"
)
data.newAltFound = true
end
data.altLogging = data.altLogging - 1
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:DiscordAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local data = client.ixAltData
if (!data.newAltFound) then return end
local tbl = {
embeds = {{
title = "Alt found for "..client:SteamName(),
description = "An alt account match was found for **"..client:SteamName().."** (*"..client:SteamID64().."*)\n\n__COOKIE__: 99.99% certainty via installed cookie\nShown as 'SteamID64 (SteamName)'\n__TIMESTAMP__: check via installation date/time or absense of mounted games (hl2,ep2,css,csgo,gmod)\nMore matches = more certainty, especially if all/most are installed\nShown as 'SteamID64 (SteamName; date/time matches - installed matches)'\n__IP__: users that connected from the same IP address at any point\nShown as 'SteamID64'",
color = 13632027,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
},
fields = {
}
}}
}
if (data.discordAlert.cookies and #data.discordAlert.cookies > 0) then
table.insert(tbl.embeds[1].fields, {name = "COOKIE", value = table.concat(data.discordAlert.cookies, "\n")})
end
if (data.discordAlert.timestamps and #data.discordAlert.timestamps > 0) then
table.insert(tbl.embeds[1].fields, {name = "TIMESTAMP", value = table.concat(data.discordAlert.timestamps, "\n")})
end
if (data.discordAlert.ips and #data.discordAlert.ips > 0) then
table.insert(tbl.embeds[1].fields, {
name = "IP",
value = string.format("Address: [%s](https://proxycheck.io/threats/%s)\n", data.ipAddress, data.ipAddress)..
table.concat(data.discordAlert.ips, "\n")
})
end
local ipLinks = {"["..client:SteamID64().."](https://steamidfinder.com/lookup/"..client:SteamID64().."/)"}
for k in pairs(data.discordAlert.altIDs) do
ipLinks[#ipLinks + 1] = "["..k.."](https://steamidfinder.com/lookup/"..k.."/)"
end
table.insert(tbl.embeds[1].fields, {
name = "SteamID Finder Links",
value = table.concat(ipLinks,"\n")
})
for _, field in ipairs(tbl.embeds[1].fields) do
if (string.len(field.value) > 1024) then
field.value = string.sub(field.value, 1, 1024)
end
end
local request = {
failed = function(error) print("discord error", error) end,
success = function(code, body, headers)
if (code != 200) then print("discord error", code, body) end
end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:ProxyAlert(client)
if (!self.DISCORD_WEBHOOK_ALTS or self.DISCORD_WEBHOOK_ALTS == "") then return end
local ip, steamID = client.ixAltData.ipAddress, client:SteamID64()
local tbl = {
embeds = {{
title = "New player using VPN - "..client:SteamName(),
description = client:SteamName().." joined WN for the first time, but was using a proxy/VPN. They have been kicked.\n\n"..
string.format("More info: [%s](https://proxycheck.io/threats/%s) & [%s](https://steamidfinder.com/lookup/%s/)", ip, ip, steamID, steamID),
color = 16312092,
timestamp = os.date("%Y-%m-%d %X%z"),
footer = {
text = "Bastion Alt Checker for GMod by Gr4Ss"
},
author = {
name = "Bastion Alt Checker"
}
}}
}
local request = {
failed = function(error) print("discord error", error) end,
method = "post",
url = self.DISCORD_WEBHOOK_ALTS,
body = util.TableToJSON(tbl),
type = "application/json; charset=utf-8"
}
CHTTP(request)
end
function PLUGIN:NotifyProxyJoin(client)
local bSend = false
for _, v in ipairs(player.GetAll()) do
if (CAMI.PlayerHasAccess(v, "Helix - Proxy Notify")) then
bSend = true
v:NotifyLocalized("bastionProxyNotify", client:SteamName())
end
end
return bSend
end

View File

@@ -0,0 +1,461 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local IsValid = IsValid
local string = string
local os = os
local print = print
local util = util
local CHTTP = CHTTP
local ipairs = ipairs
local table = table
local pairs = pairs
local netstream = netstream
local SortedPairsByMemberValue = SortedPairsByMemberValue
local PLUGIN = PLUGIN
local MAX_CACHE_AGE = 7 * 24 * 3600 -- 7 days
PLUGIN.ipCache = {}
hook.Add("DatabaseConnected", "bastionAntiAlt", function()
local query = mysql:Create("bastion_antialt_users")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(128) NOT NULL")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_cookies")
query:Create("cookie", "VARCHAR(64) NOT NULL")
query:Create("ts_hl2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_ep2", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_css", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_csgo", "INT(11) UNSIGNED DEFAULT NULL")
query:Create("ts_gmod", "INT(11) UNSIGNED DEFAULT NULL")
query:PrimaryKey("cookie")
query:Execute()
query = mysql:Create("bastion_antialt_userips")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("last_seen", "INT(11) UNSIGNED NOT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_antialt_ip")
query:Create("ip", "VARCHAR(15) NOT NULL")
query:Create("updated", "INT(11) UNSIGNED NOT NULL")
query:Create("asn", "VARCHAR(12) NOT NULL")
query:Create("provider", "VARCHAR(128) NOT NULL")
query:Create("isocode", "VARCHAR(2) NOT NULL")
query:Create("proxy", "TINYINT(1) UNSIGNED DEFAULT 0")
query:Create("type", "VARCHAR(32) NOT NULL")
query:Create("risk", "INT UNSIGNED NOT NULL")
query:Create("attack_count", "INT UNSIGNED DEFAULT NULL")
query:Create("attack_history", "TEXT DEFAULT NULL")
query:PrimaryKey("ip")
query:Execute()
query = mysql:Create("bastion_antialt_alts")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("alt_id", "INT UNSIGNED NOT NULL")
query:Create("type", "VARCHAR(10) NOT NULL")
query:Create("info", "TEXT NOT NULL")
query:PrimaryKey("steamid")
query:Execute()
end)
function PLUGIN:AltLoadUserData(client)
local query = mysql:Select("bastion_antialt_users")
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client.ixAltData.mode = self.TYPE_UNKNOWN
else
client.ixAltData.mode = self.TYPE_KNOWN
client.ixAltData.cookies = result
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN.GetIPAddress(client)
local ip = client:IPAddress()
return string.gsub(ip, ":%d+$", "", 1)
end
function PLUGIN:AltLookupIP(client)
local ip = self.GetIPAddress(client)
client.ixAltData.ipAddress = ip
if (self.ipCache[ip]) then
-- ip address still in cache
client.ixAltData.ip = self.ipCache[ip]
self:AltPreFinalChecking(client)
else
-- lookup address
local query = mysql:Select("bastion_antialt_ip")
query:Where("ip", ip)
query:Callback(function(result)
if (!result or #result == 0 or (result[1].updated < (os.time() - MAX_CACHE_AGE))) then
self:AltFetchIP(client, ip, !result or #result == 0)
else
-- load in data from the DB
if (result[1].proxy == 1) then
result[1].proxy = "yes"
else
result[1].proxy = "no"
end
client.ixAltData.ip = result[1]
self:AltPreFinalChecking(client)
end
end)
query:Execute()
end
end
function PLUGIN:AltFetchIP(client, ip, bCreateNew)
-- address not found or record too old, look it up
local url = string.format("https://proxycheck.io/v2/%s?key=%s&vpn=1&asn=1&risk=1", ip, self.API_KEY)
local request = {
failed = function(error)
-- error stop matching
print("[BASTION] Alt check IP API call failed with error: "..error)
print("[BASTION] Client: "..client:SteamName().."; ip: "..ip)
client.ixAltData.error = true
end,
success = function(code, body, headers)
if (!IsValid(client)) then return end
local httpResult = util.JSONToTable(body)
if (!httpResult) then
-- error stop matching
print("[BASTION] Alt check IP API call failed to parse httpResult.")
client.ixAltData.error = true
return
end
local status = httpResult.status
if (status == "denied" or status == "error" or status == "warning") then
print("[BASTION] Alt check IP API call failed. Status: "..status.."; Message: "..(httpResult.message or "no message").."\n")
if (status != "warning") then
-- error stop matching
client.ixAltData.error = true
return
end
end
-- we got the data
local lookup = httpResult[ip]
self:StoreIPLookup(ip, lookup, bCreateNew)
client.ixAltData.ip = lookup
self:AltPreFinalChecking(client)
end,
url = url,
method = "GET"
}
CHTTP(request)
end
function PLUGIN:AltLookupCookieMatches(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
-- we found other cookies
if (result and #result > 0) then
for k, v in ipairs(result) do
data.otherCookies[k] = {v.steam_name, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupIPMatches(client)
local query = mysql:Select("bastion_antialt_userips")
query:Where("ip", PLUGIN.GetIPAddress(client))
query:WhereNotEqual("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for k, v in ipairs(result) do
client.ixAltData.otherIPs[k] = {v.ip, v.steamid}
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AltLookupTimestampMatches(client, data, game, timestamp)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("ts_"..game, timestamp)
if (data.localCookie != "") then
-- not interested in timestamps that we know for this client
query:WhereNotEqual("cookie", data.localCookie)
end
query:Callback(function(result)
if (result and #result > 0) then
for _, v in ipairs(result) do
data.otherTimestamps[v.cookie] = data.otherTimestamps[v.cookie] or {}
table.insert(data.otherTimestamps[v.cookie], game)
-- track timestamp matches
-- non-zero timestamps are worth a lot more, so tracked separately too
if (timestamp != 0) then
data.otherTimestampsNZ[v.cookie] = data.otherTimestampsNZ[v.cookie] or {}
data.otherTimestampsNZ[v.cookie][game] = true
end
end
end
self:AltPreFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:AggregateTimestampMatches(data)
data.otherTimeMatches = {}
for cookie, matches in pairs(data.otherTimestamps) do
if (#matches == 1) then continue end
data.otherTimeMatches[#data.otherTimeMatches + 1] = {cookie, #matches}
end
table.SortByMember(data.otherTimeMatches, 2, false)
end
function PLUGIN:AltLookupCookieForTimestamps(client, data, maxMatches)
local cookies = {}
for cookie, matches in pairs(data.otherTimestamps) do
-- only find cookies if at least 2 matches of which one is non-zero
if (#matches >= 2 and data.otherTimestampsNZ[cookie]) then
cookies[#cookies + 1] = cookie
end
end
if (#cookies == 0) then
data.checkComplete = true
self:AltFinalChecking(client)
return
end
local query = mysql:Select("bastion_antialt_users")
query:WhereNotEqual("steamid", client:SteamID64())
query:WhereIn("cookie", cookies)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (result and #result > 0) then
for _, v in ipairs(result) do
local installed = table.GetKeys(data.otherTimestampsNZ[v.cookie])
local text = string.format("%d/%d matches - installed: %s)",
#data.otherTimestamps[v.cookie],
maxMatches,
table.concat(installed, "+")
)
self:AltFound(client, v.steamid, "timestamp", text)
data.discordAlert.timestamps[# data.discordAlert.timestamps + 1] = v.steamid.." ("..v.steam_name.."; "..text..")"
data.discordAlert.altIDs[v.steamid] = true
end
end
data.checkComplete = true
self:AltFinalChecking(client)
end)
query:Execute()
end
function PLUGIN:StoreCookieInfo(data, fileChecks)
local query = mysql:Select("bastion_antialt_cookies")
query:Where("cookie", data.localCookie)
query:Callback(function(result)
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_cookies")
queryInsert:Insert("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryInsert:Insert("ts_"..v[2], data.timestamps[k])
end
queryInsert:Execute()
else
local queryUpdate = mysql:Update("bastion_antialt_cookies")
queryUpdate:Where("cookie", data.localCookie)
for k, v in ipairs(fileChecks) do
queryUpdate:Update("ts_"..v[2], data.timestamps[k])
end
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreClientCookie(client, data)
local query = mysql:Select("bastion_antialt_users")
query:Where("cookie", data.localCookie)
query:Where("steamid", client:SteamID64())
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
local queryInsert = mysql:Insert("bastion_antialt_users")
queryInsert:Insert("steamid", client:SteamID64())
queryInsert:Insert("steam_name", client:SteamName())
queryInsert:Insert("cookie", data.localCookie)
queryInsert:Execute()
end
end)
query:Execute()
end
function PLUGIN:StoreIPLookup(ip, httpResult, bNewEntry)
if (!bNewEntry) then
local query = mysql:Update("bastion_antialt_ip")
query:Where("ip", ip)
query:Update("updated", os.time())
query:Update("asn", httpResult.asn)
query:Update("provider", httpResult.provider)
query:Update("isocode", httpResult.isocode)
query:Update("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Update("type", httpResult.type)
query:Update("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Update("attack_count", httpResult["attack history"].Total)
query:Update("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
else
local query = mysql:Insert("bastion_antialt_ip")
query:Insert("ip", ip)
query:Insert("updated", os.time())
query:Insert("asn", httpResult.asn)
query:Insert("provider", httpResult.provider)
query:Insert("isocode", httpResult.isocode)
query:Insert("proxy", httpResult.proxy == "yes" and 1 or 0)
query:Insert("type", httpResult.type)
query:Insert("risk", httpResult.risk or 0)
if (httpResult["attack history"]) then
query:Insert("attack_count", httpResult["attack history"].Total)
query:Insert("attack_history", util.TableToJSON(httpResult["attack history"]))
end
query:Execute()
end
end
function PLUGIN:InsertNewAlt(steamid, alt_id, type, text)
local query = mysql:Insert("bastion_antialt_alts")
query:Insert("steamid", steamid)
query:Insert("alt_id", alt_id)
query:Insert("type", type)
query:Insert("info", text)
query:Execute()
end
function PLUGIN:MergeAlts(old_id, new_id, text)
local query = mysql:Select("bastion_antialt_alts")
query:Where("alt_id", old_id)
query:Callback(function(result2)
for _, v in ipairs(result2) do
local queryUpdate = mysql:Update("bastion_antialt_alts")
queryUpdate:Where("steamid", v.steamid)
queryUpdate:Update("alt_id", new_id)
queryUpdate:Update("info", v.info.." - "..text)
queryUpdate:Execute()
end
end)
query:Execute()
end
function PLUGIN:LookupSteamID(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64()
end
local query = mysql:Select("bastion_antialt_alts")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local querySelect = mysql:Select("bastion_antialt_alts")
querySelect:Where("alt_id", result[1].alt_id)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
local toReturn = {"Alts for "..steamid..":", "(SteamID64) - (detection trigger type) - (info)"}
for _, v in ipairs(finalResult) do
toReturn[#toReturn + 1] = v.steamid.." - "..v.type.." - info: "..v.info
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end
function PLUGIN:LookupIPUsers(client, steamid)
if (string.find(steamid, "^STEAM_")) then
steamid = util.SteamIDTo64(steamid)
end
local query = mysql:query("bastion_antialt_userips")
query:Where("steamid", steamid)
query:Callback(function(result)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local list = {}
for k, v in ipairs(result) do
list[k] = v.ip
end
local querySelect = mysql:query("bastion_antialt_userips")
querySelect:WhereIn("ip", list)
querySelect:WhereNotEqual("steamid", steamid)
querySelect:Callback(function(finalResult)
if (!IsValid(client)) then return end
if (!result or #result == 0) then
client:NotifyLocalized("bastionNoRecordFound", steamid)
return
end
local toReturn = {"Other users on same IP as "..steamid, "(SteamID64) - (ip) - (last seen on this ip)"}
for _, v in SortedPairsByMemberValue(finalResult, "steamid") do
toReturn[#toReturn + 1] = v.steamid.." - "..v.ip.." - "..os.date("%Y-%m-%d", v.last_seen)
end
netstream.Start(client, "PrintInfoList", toReturn)
client:NotifyLocalized("bastionResultsPrinted")
end)
querySelect:Execute()
end)
query:Execute()
end

View File

@@ -0,0 +1,96 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook = hook
local ix = ix
local util = util
local PLUGIN = PLUGIN
PLUGIN.permaBan = {
-- Crazyman (~Atle/Gr4Ss), code stealing
["STEAM_0:1:120921609"] = true,
["2.73.226.221"] = true,
["2.72.176.41"] = true,
["2.132.96.235"] = true,
["2.132.103.122"] = true,
["2.132.147.172"] = true,
["2.132.150.162"] = true,
["95.57.132.81"] = true,
-- carlsmei (~Atle/Gr4Ss), code stealing
["STEAM_0:0:216726444"] = true,
-- Schwarz Kruppzo (~Atle/Gr4Ss), code stealing
["STEAM_0:1:44629398"] = true,
-- KoC (~Atle/Gr4Ss), toxic, ban evasion
["76561198017957016"] = true,
["76561199123547331"] = true,
["73.121.218.83"] = true,
["136.144.43.116"] = true,
["136.144.43.63"] = true,
-- Kalingi (Staff vote, Hiros/Gr4Ss), toxic, threatening hacks & blackmail
["76561198066620287"] = true,
["STEAM_0:1:53177279"] = true,
["24.197.171.2"] = true,
-- Brando (~Atle/Gr4Ss), pedo
["STEAM_0:1:54660756"] = true,
-- Walter (~Atle/Gr4Ss), none
["STEAM_0:1:43085888"] = true,
-- PrplSckz/The Enemy (~Rad/Gr4Ss), forum DDoS
["STEAM_0:1:68538156"] = true,
-- Hackers (~Gr4Ss)
["STEAM_0:1:13809165"] = true,
["STEAM_0:1:4916602"] = true,
["STEAM_0:1:517232907"] = true,
["STEAM_0:1:17046093"] = true,
-- Exploiters
["STEAM_0:0:549109050"] = true,
["76561199131288084"] = true,
["76561199087140341"] = true,
["76561199206105794"] = true,
["76561198874018211"] = true,
["109.252.109.68"] = true,
["76561199121843993"] = true,
-- Zeroday / Newport Gaming - Sketchy dude + some hacking & exploiting (~M!NT/RAD)
["172.82.32.147"] = true,
["76561199441966033"] = true,
-- Cazo
["82.0.106.136"] = true,
["76561199150421701"] = true,
-- lqut (Translating ISIS Propaganda) (~M!NT/RAD)
["STEAM_0:0:173208852"] = true,
["5.30.219.71"] = true,
["76561198306683432"] = true,
-- madbluntz (doxxing, minging, ddosing, etc etc) (~M!NT)
["176.117.229.107"] = true,
["176.117.229.107"] = true,
["178.214.250.178"] = true,
["46.191.232.69"] = true,
["178.168.94.11"] = true,
["163.182.82.195"] = true,
["104.231.185.125"] = true,
["STEAM_0:0:763201893"] = true,
["STEAM_0:0:629741416"] = true,
["STEAM_0:1:764405213"] = true,
["STEAM_0:1:817531224"] = true,
["STEAM_0:0:785033797"] = true,
["STEAM_0:1:421783352"] = true,
["STEAM_0:1:78544439"] = true,
["STEAM_0:1:178702634"] = true,
["STEAM_0:0:627119036"] = true,
["STEAM_0:0:585787645"] = true,
["STEAM_0:1:43085888"] = true,
}
hook.Add("CheckPassword", "bastionBanList", function(steamid, networkid)
if (PLUGIN.permaBan[steamid] or PLUGIN.permaBan[util.SteamIDFrom64(steamid)] or PLUGIN.permaBan[networkid]) then
ix.log.AddRaw("[BANS] "..steamid.." ("..networkid..") tried to connect but is hard-banned.")
return false
end
end)

View File

@@ -0,0 +1,211 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local hook_Add = hook.Add
local timer_Create = timer.Create
local os_time = os.time
local pairs = pairs
local net_ReadHeader = net.ReadHeader
local util_NetworkIDToString = util.NetworkIDToString
local ix = ix
local IsValid = IsValid
local string_len = string.len
local string_sub = string.sub
-- Code inspired by:
-- Gmod Net Library Debug
-- https://github.com/HexaneNetworks/gmod-netlibrary-debug
-- v2.3
-- October 2020
local PLUGIN = PLUGIN
hook_Add("DatabaseConnected", "bastionNetDB", function()
local query = mysql:Create("bastion_netlog")
query:Create("id", "BIGINT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("length", "INT UNSIGNED NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("args", "VARCHAR(200) DEFAULT NULL")
query:PrimaryKey("id")
query:Execute()
query = mysql:Create("bastion_netspam")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("name", "VARCHAR(50) NOT NULL")
query:Create("type", "BOOL NOT NULL")
query:Create("count", "INT UNSIGNED NOT NULL")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("steam_name", "VARCHAR(50) NOT NULL")
query:Create("ip", "VARCHAR(25) NOT NULL")
query:Create("time", "INT NOT NULL")
query:PrimaryKey("id")
query:Execute()
end)
local netSpamCount = {}
local netFlagged = {}
local comSpamCount = {}
local comFlagged = {}
local threshold = 20
timer_Create("ixBastionNetSpam.Clear", 1.1, 0, function()
local time = os_time()
for steamID, data in pairs(netFlagged) do
for name in pairs(data.names) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 0)
query:Insert("count", netSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
netSpamCount = {}
netFlagged = {}
for steamID, data in pairs(comFlagged) do
for name in pairs(data.commands) do
local query = mysql:Insert("bastion_netspam")
query:Insert("name", name)
query:Insert("type", 1)
query:Insert("count", comSpamCount[steamID][name] or 0)
query:Insert("steamid", steamID)
query:Insert("steam_name", data.steamName)
query:Insert("ip", data.ip)
query:Insert("time", time)
query:Execute()
end
end
comSpamCount = {}
comFlagged = {}
end)
local netIgnoreList = {
["76561198002319953"] = 2
}
local netSpamAmount = {
["NetStreamDS"] = 20,
["76561198002319953"] = 30
}
function net.Incoming(len, client)
local i = net_ReadHeader()
local name = util_NetworkIDToString(i)
if (!name) then return end
local func = net.Receivers[name:lower()]
if (!func) then return end
--
-- len includes the 16 bit int which told us the message name
--
len = len - 16
if (ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
netSpamCount[steamID] = netSpamCount[steamID] or {}
netSpamCount[steamID][name] = (netSpamCount[steamID][name] or 0) + 1
if (netSpamCount[steamID][name] > (netSpamAmount[name] or threshold)) then
if (!netFlagged[steamID]) then
netFlagged[steamID] = {
names = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
netFlagged[steamID].names[name] = true
end
if (ix.config.Get("netLoggingEnabled") and (!netIgnoreList[name] or netIgnoreList[name] < netSpamCount[steamID][name])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", name)
query:Insert("length", len)
query:Insert("count", netSpamCount[steamID][name])
query:Insert("steamid", steamID)
query:Execute()
end
end
func(len, client)
end
local conSpamAmount = {
}
local conIgnoreList = {
}
PLUGIN.oldRun = PLUGIN.oldRun or concommand.Run
function concommand.Run(client, command, args, argString)
if (IsValid(client) and command and ix.config.Get("netAntiSpam")) then
local steamID = IsValid(client) and client:SteamID64() or "UNKNOWN"
comSpamCount[steamID] = comSpamCount[steamID] or {}
comSpamCount[steamID][command] = (comSpamCount[steamID][command] or 0) + 1
if (comSpamCount[steamID][command] > (conSpamAmount[command] or threshold)) then
if (!comFlagged[steamID]) then
comFlagged[steamID] = {
commands = {},
steamID = steamID,
steamName = IsValid(client) and (client.SteamName and client:SteamName() or client:Name()) or "UNKNOWN PLAYER NAME",
ip = IsValid(client) and client:IPAddress() or "UNKNOWN IP"
}
if (!ix.config.Get("netLoggingEnabled")) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", netSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
comFlagged[steamID].commands[command] = true
end
if (ix.config.Get("netLoggingEnabled") and (!conIgnoreList[command] or conIgnoreList[command] < comSpamCount[steamID][command])) then
local query = mysql:Insert("bastion_netlog")
query:Insert("name", command)
query:Insert("length", #argString)
query:Insert("count", comSpamCount[steamID][command])
query:Insert("steamid", steamID)
query:Insert("args", string_len(argString or "") > 200 and string_sub(argString, 1, 200) or argString or "")
query:Execute()
end
end
return PLUGIN.oldRun(client, command, args, argString)
end

View File

@@ -0,0 +1,100 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLUGIN = PLUGIN
--Made by Liquid
PLUGIN.MIN_PLAYER_COUNT = 30
PLUGIN.STOP_AFTER_CONNECTED_FOR = 600
PLUGIN.MIN_SIZE = 100
PLUGIN.TRACE_SIZE = 1000
ORIGINAL_NET = ORIGINAL_NET or table.Copy(net)
local _net = ORIGINAL_NET
local IsValid = IsValid
local currentMessageName
hook.Add("DatabaseConnected", "bastionNetSizeLog", function()
local query = mysql:Create("bastion_netsizelog")
query:Create("id", "INT UNSIGNED NOT NULL AUTO_INCREMENT")
query:Create("steamid", "VARCHAR(20) NOT NULL")
query:Create("timestamp", "INT(11) UNSIGNED NOT NULL")
query:Create("realtime", "FLOAT NOT NULL")
query:Create("message_name", "VARCHAR(128) NOT NULL")
query:Create("size", "INT(11) UNSIGNED NOT NULL")
query:Create("stack_trace", "TEXT DEFAULT NULL")
query:PrimaryKey("id")
query:Callback(function()
local delete = mysql:Delete("bastion_netsizelog")
delete:WhereLT("timestamp", os.time() - 3 * 24 * 3600)
delete:Execute()
end)
query:Execute()
end)
local function netLog(players)
local count = player.GetCount()
if (count > 1 and count <= PLUGIN.MIN_PLAYER_COUNT) then return end
if (type(players) == "Player") then
players = {players}
elseif (type(players) == "CRecipientFilter") then
players = players:GetPlayers()
end
local size = _net.BytesWritten()
if (size <= PLUGIN.MIN_SIZE) then return end
for k, v in ipairs(players) do
if (!IsValid(v)) then continue end
if (v.ixStopNetLog or v:TimeConnected() > PLUGIN.STOP_AFTER_CONNECTED_FOR) then
v.ixStopNetLog = true
continue
end
local query = mysql:Insert("bastion_netsizelog")
query:Insert("steamid", v:SteamID64())
query:Insert("timestamp", os.time())
query:Insert("realtime", RealTime())
query:Insert("message_name", currentMessageName)
query:Insert("size", size)
if (size >= PLUGIN.TRACE_SIZE or currentMessageName == "NetStreamDS") then
query:Insert("stack_trace", debug.traceback())
end
query:Execute()
end
end
net.Start = function(name, unreliable)
currentMessageName = name
return _net.Start(name, unreliable)
end
net.Send = function(players)
netLog(players)
currentMessageName = nil
return _net.Send(players)
end
net.SendOmit = function(players)
netLog(players)
currentMessageName = nil
return _net.SendOmit(players)
end
net.Broadcast = function(pos)
netLog(player.GetAll())
currentMessageName = nil
return _net.Broadcast()
end