From a08f5a10bf3b23dd24c3fb4369488ccc4d989e8c Mon Sep 17 00:00:00 2001 From: jenz Date: Sat, 9 Apr 2022 19:59:58 +0200 Subject: [PATCH] initial release of nosteam ASN verification --- .../scripting/nosteam_verifier.sp | 352 ++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 nosteam_verificiation/scripting/nosteam_verifier.sp diff --git a/nosteam_verificiation/scripting/nosteam_verifier.sp b/nosteam_verificiation/scripting/nosteam_verifier.sp new file mode 100644 index 00000000..8de8d931 --- /dev/null +++ b/nosteam_verificiation/scripting/nosteam_verifier.sp @@ -0,0 +1,352 @@ +#pragma semicolon 1 +#define PLUGIN_AUTHOR "jenz but with stuff from neons vpn checker" +#define PLUGIN_VERSION "1.0" +#define APIKEY "30r040-2w8k51-711148-8118n3" +#pragma newdecls optional +#include +#pragma newdecls required +#include +#include +#include +#include + +Database g_hDatabase; +Database g_hDatabase_sourceban; + +char g_asn[MAXPLAYERS + 1][65]; +char g_provider[MAXPLAYERS + 1][65]; +char g_country[MAXPLAYERS + 1][65]; + +public Plugin myinfo = +{ + name = "verifying nosteamers", + author = PLUGIN_AUTHOR, + description = "verifies nosteamers", + version = PLUGIN_VERSION, + url = "www.unloze.com" +}; + +//the point of this plugin is simple to handle nosteamers abusing dynamic networks instead of having a static network +public void OnPluginStart() +{ + Database.Connect(SQL_OnDatabaseConnect, "PlayerManager"); + Database.Connect(SQL_OnDatabaseConnect_sb, "sourcebans"); +} + +public void SQL_OnDatabaseConnect(Database db, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Database error: %s", error); + return; + } + g_hDatabase = db; + char sQuery[512]; + Format(sQuery, sizeof(sQuery), "CREATE TABLE if not exists `sb_bans_shortened` (`steam_id` varchar(64) NOT NULL, `ipv4` varchar(64) NOT NULL, PRIMARY KEY (`steam_id`,`ipv4`))"); + g_hDatabase.Query(sql_insert_dummy, sQuery, _, DBPrio_High); + Format(sQuery, sizeof(sQuery), "CREATE TABLE if not exists `connect_restriction` (`country` varchar(64) DEFAULT NULL, `asn` varchar(128) DEFAULT NULL, `provider` varchar(128) DEFAULT NULL, `cooldown` datetime DEFAULT NULL, `steam_id` varchar(64) NOT NULL, `ipv4` varchar(64) NOT NULL, `inserted_on` datetime DEFAULT current_timestamp(), `modified_on` datetime DEFAULT current_timestamp() ON UPDATE current_timestamp(), PRIMARY KEY (`steam_id`,`ipv4`))"); + g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, _, DBPrio_High); +} + +public void SQL_OnDatabaseConnect_sb(Database db, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Database error: %s", error); + return; + } + g_hDatabase_sourceban = db; + for (int i = 1; i <= MaxClients; i++) + OnClientPostAdminCheck(i); +} + +public void SQL_OnQueryCompleted(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + delete results; + for (int i = 1; i <= MaxClients; i++) + OnClientPostAdminCheck(i); +} + +public int OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, int iSerial) +{ + if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + { + delete hRequest; + LogError("Request-Error: %d", eStatusCode); + return; + } + SteamWorks_GetHTTPResponseBodyCallback(hRequest, OnTransferResponse, iSerial); +} + +public int OnTransferResponse(char[] sData, int iSerial) +{ + int client = GetClientFromSerial(iSerial); + if (!client) //Player disconnected. + return; + + char sIP[32]; + GetClientIP(client, sIP, sizeof(sIP)); + + JSON_Object obj = json_decode(sData); + char sStatus[32]; + obj.GetString("status", sStatus, sizeof(sStatus)); + if (!StrEqual(sStatus, "ok") && !StrEqual(sStatus, "warning")) + { + char sMessage[256]; + obj.GetString("message", sMessage, sizeof(sMessage)); + LogError("API-Response: %s: %s", sStatus, sMessage); + obj.Cleanup(); + delete obj; + return; + } + JSON_Object ipobj = obj.GetObject(sIP); + char asn[64]; + char provider[64]; + char country[64]; + ipobj.GetString("asn", asn, sizeof(asn)); + ipobj.GetString("provider", provider, sizeof(provider)); + ipobj.GetString("country", country, sizeof(country)); + + char sql_statement[512]; + char sAuthID[512]; + Format(g_asn[client], sizeof(g_asn[]), asn); + Format(g_provider[client], sizeof(g_provider[]), provider); + Format(g_country[client], sizeof(g_country[]), country); + + GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false); + Format(sql_statement, sizeof(sql_statement), "insert into connect_restriction (country, asn, provider, steam_id, ipv4) values ('%s', '%s', '%s', '%s', '%s') ON DUPLICATE KEY UPDATE modified_on = now()", country, asn, provider, sAuthID, sIP); + g_hDatabase.Query(SQL_insert, sql_statement, iSerial, DBPrio_High); + ipobj.Cleanup(); + delete ipobj; + obj.Cleanup(); + delete obj; +} + +public void SQL_insert(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "update connect_restriction cr1 inner join (select * from connect_restriction cr3 where cr3.asn = '%s' and cr3.provider = '%s' and cr3.country = '%s' and cr3.cooldown > CURDATE() order by cr3.inserted_on desc limit 1) as cr2 on cr1.asn = cr2.asn and cr1.provider = cr2.provider and cr1.country = cr2.country set cr1.cooldown = cr2.cooldown", g_asn[client], g_provider[client], g_country[client]); + delete results; + g_hDatabase.Query(SQL_update_restriction, sql_statement, GetClientSerial(client), DBPrio_High); +} + +public void SQL_update_restriction(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + delete results; + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "select * from connect_restriction where asn = '%s' and provider = '%s' and country = '%s' and cooldown > CURDATE() order by inserted_on desc limit 1", g_asn[client], g_provider[client], g_country[client]); + g_hDatabase.Query(sql_select_cooldown, sql_statement, GetClientSerial(client), DBPrio_High); +} + +public void sql_select_cooldown(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + if (results.RowCount && results.FetchRow()) + { + KickClient(client, "If you believe this is undeserved write a forum post on https://www.unloze.com"); + } + else + { + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "TRUNCATE table `sb_bans_shortened`"); + g_hDatabase.Query(sql_truncate_sb_bans_shortened, sql_statement, GetClientSerial(client), DBPrio_High); + } + delete results; +} + +public void OnMapStart() +{ + if (!g_hDatabase) + return; + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "TRUNCATE table `sb_bans_shortened`"); + g_hDatabase.Query(sql_truncate_sb_bans_shortened, sql_statement, _, DBPrio_High); +} + +public void sql_truncate_sb_bans_shortened(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error truncate: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "select distinct ip, authid from sb_bans where ip is not null and ip != '' and authid is not null and authid != '' and (ends = created or ends > UNIX_TIMESTAMP())"); + g_hDatabase_sourceban.Query(sql_select_sb_bans, sql_statement, GetClientSerial(client), DBPrio_High); + delete results; +} + +public void sql_select_sb_bans(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + char s_client_ip[64]; + GetClientIP(client, s_client_ip, sizeof(s_client_ip)); + char sql_statement[2856]; + + //in case that very last client exceeds 2700 + bool after_result = true; + Format(sql_statement, sizeof(sql_statement), "INSERT IGNORE INTO `sb_bans_shortened` (`steam_id`,`ipv4`) VALUES "); + while (results.RowCount && results.FetchRow()) + { + char sIP[64]; + char sAuthID[64]; + results.FetchString(0, sIP, sizeof(sIP)); + results.FetchString(1, sAuthID, sizeof(sAuthID)); + Format(sql_statement, sizeof(sql_statement), "%s ('%s','%s'),", sql_statement, sAuthID, sIP); + if (strlen(sql_statement) > 2700) + { + Format(sql_statement, strlen(sql_statement), sql_statement); + g_hDatabase.Query(sql_insert_dummy, sql_statement, _, DBPrio_High); + Format(sql_statement, sizeof(sql_statement), "INSERT IGNORE INTO `sb_bans_shortened` (`steam_id`,`ipv4`) VALUES "); + after_result = false; + } + after_result = true; + } + Format(sql_statement, strlen(sql_statement), sql_statement); + if (after_result) + { + g_hDatabase.Query(sql_insert_dummy, sql_statement, _, DBPrio_High); + } + delete results; + Format(sql_statement, sizeof(sql_statement), "select cr1.* from connect_restriction cr1 inner join connect_restriction cr2 on cr1.asn = cr2.asn inner join sb_bans_shortened cr3 on cr1.steam_id = cr3.steam_id and cr1.ipv4 = cr3.ipv4 and cr1.provider = cr2.provider and cr1.country = cr2.country and cr2.ipv4 = '%s' limit 1", s_client_ip); + g_hDatabase.Query(sql_select_banned, sql_statement, GetClientSerial(client), DBPrio_High); +} + +public void sql_insert_dummy(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error)) + { + LogError("Query error dummy: %s", error); + return; + } +} + +//checks sourceban active bans to see if adding cooldown +public void sql_select_banned(Database db, DBResultSet results, const char[] error, any data) +{ + if (!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + if (results.RowCount && results.FetchRow()) + { + char s_client_ip[64]; + GetClientIP(client, s_client_ip, sizeof(s_client_ip)); + char sAuthID[512]; + GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false); + char sql_statement[512]; + Format(sql_statement, sizeof(sql_statement), "update connect_restriction set cooldown = DATE_ADD(now(), INTERVAL 170 DAY) where steam_id = '%s' and ipv4 = '%s'", sAuthID, s_client_ip); + g_hDatabase.Query(sql_update_cooldown, sql_statement, GetClientSerial(client), DBPrio_High); + } + delete results; +} + +public void sql_update_cooldown(Database db, DBResultSet results, const char[] error, any data) +{ + if(!db || strlen(error)) + { + LogError("Query error: %s", error); + return; + } + int client; + if ((client = GetClientFromSerial(data)) == 0) + return; + delete results; + KickClient(client, "If you believe this is undeserved write a forum post on https://www.unloze.com"); +} + +public void resetClient(int client) +{ + Format(g_asn[client], sizeof(g_asn[]), ""); + Format(g_provider[client], sizeof(g_provider[]), ""); + Format(g_country[client], sizeof(g_country[]), ""); +} + +public void OnClientDisconnect(int client) +{ + resetClient(client); +} + +public void OnClientPostAdminCheck(int client) +{ + if(!IsValidClient(client) || IsFakeClient(client)) + return; + if (!g_hDatabase) + { + Database.Connect(SQL_OnDatabaseConnect, "PlayerManager"); + return; + } + if (!g_hDatabase_sourceban) + { + Database.Connect(SQL_OnDatabaseConnect_sb, "sourcebans"); + return; + } + resetClient(client); + char sAuthID[32]; + GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false); + if (!SteamClientAuthenticated(sAuthID)) + { + char sAddress[16]; + GetClientIP(client, sAddress, sizeof(sAddress)); + char sRequest[256]; + FormatEx(sRequest, sizeof(sRequest), "https://proxycheck.io/v2/%s?key=%s&asn=1", sAddress, APIKEY); + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); + if (!hRequest || + !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || + !SteamWorks_SetHTTPRequestContextValue(hRequest, GetClientSerial(client)) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + delete hRequest; + } + } +} + +stock bool IsValidClient(int client) +{ + if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)) + return true; + return false; +} +