452 lines
18 KiB
SourcePawn
452 lines
18 KiB
SourcePawn
#pragma semicolon 1
|
|
#define PLUGIN_AUTHOR "jenz but with stuff from neons vpn checker"
|
|
#define PLUGIN_VERSION "1.0"
|
|
#define APIKEY "mfg242-532328-b34d06-5a8262"
|
|
#pragma newdecls optional
|
|
#include <SteamWorks>
|
|
#pragma newdecls required
|
|
#include <sourcemod>
|
|
#include <basecomm>
|
|
#include <connect>
|
|
#include <json>
|
|
|
|
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 OnMapStart()
|
|
{
|
|
CreateTimer(5.0, time_query_nosteam_select, INVALID_HANDLE, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
public Action time_query_nosteam_select(Handle timer, any data)
|
|
{
|
|
for (int client = 1; client <= MaxClients; client++)
|
|
if (IsValidClient(client) && !IsFakeClient(client))
|
|
{
|
|
char sAuthID[32];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
char sIP[32];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
if (!SteamClientAuthenticated(sAuthID))
|
|
{
|
|
char sQuery[512];
|
|
Format(sQuery, sizeof(sQuery), "select * from kicklist cr where cr.steam_id = '%s' and cr.ipv4 = '%s' and cr.kick is TRUE", sAuthID, sIP);
|
|
g_hDatabase.Query(sql_update_cooldown, sQuery, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
|
|
}
|
|
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
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;
|
|
if (results.RowCount && results.FetchRow())
|
|
{
|
|
char sIP[64];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
char sAuthID[512];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
char sql_statement[512];
|
|
Format(sql_statement, sizeof(sql_statement), "delete from kicklist where steam_id = '%s' and ipv4 = '%s' and kick is TRUE", sAuthID, sIP);
|
|
g_hDatabase.Query(sql_kick_client, sql_statement, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
public void sql_kick_client(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 sIP[64];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
char sAuthID[512];
|
|
GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false);
|
|
LogMessage("%L | %s nosteamer got kicked for dynamic IP ban avoiding(IP: %s).", client, sAuthID, sIP);
|
|
KickClient(client, "If you believe this is undeserved write a forum post on https://www.unloze.com");
|
|
}
|
|
|
|
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(), `cooldown_query` varchar(1028) DEFAULT NULL, `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 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[1024];
|
|
g_hDatabase.Escape(provider, g_provider[client], sizeof(g_provider[]));
|
|
char sAuthID[512];
|
|
Format(g_asn[client], sizeof(g_asn[]), asn);
|
|
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, g_provider[client], 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[1024];
|
|
char sIP[64];
|
|
char ip_subblock[8][8];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
ExplodeString(sIP, ".", ip_subblock, sizeof(ip_subblock), sizeof(ip_subblock[]));
|
|
char sql_statement_query[1024];
|
|
Format(sql_statement_query, sizeof(sql_statement_query), "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.ipv4 like '%s.%s.%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 where cr1.ipv4 like '%s.%s.%s'", g_asn[client], g_provider[client], g_country[client], ip_subblock[0], ip_subblock[1], "%", ip_subblock[0], ip_subblock[1], "%");
|
|
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.ipv4 like '%s.%s.%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, cr1.cooldown_query = %s%s%s where cr1.ipv4 like '%s.%s.%s'", g_asn[client], g_provider[client], g_country[client], ip_subblock[0], ip_subblock[1], "%", "\"", sql_statement_query, "\"", ip_subblock[0], ip_subblock[1], "%");
|
|
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 sIP[64];
|
|
char ip_subblock[8][8];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
ExplodeString(sIP, ".", ip_subblock, sizeof(ip_subblock), sizeof(ip_subblock[]));
|
|
char sql_statement[512];
|
|
Format(sql_statement, sizeof(sql_statement), "select * from connect_restriction where asn = '%s' and provider = '%s' and country = '%s' and ipv4 like '%s.%s.%s' and cooldown > CURDATE() order by inserted_on desc limit 1", g_asn[client], g_provider[client], g_country[client], ip_subblock[0], ip_subblock[1], "%");
|
|
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 client already has a cooldown no further action needed
|
|
//if client has no cooldown we update sourcebans copy table
|
|
if (!results.RowCount || !results.FetchRow())
|
|
{
|
|
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 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, name from sb_bans where ip is not null and ip != '' and authid is not null and authid != '' and (RemoveType != 'U' or RemoveType is NULL) and created > UNIX_TIMESTAMP(NOW() - INTERVAL 5 DAY) and (ends > UNIX_TIMESTAMP() or ends = created) order by created desc");
|
|
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 on the last query
|
|
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);
|
|
after_result = true;
|
|
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;
|
|
}
|
|
}
|
|
Format(sql_statement, strlen(sql_statement), sql_statement);
|
|
if (after_result)
|
|
{
|
|
g_hDatabase.Query(sql_insert_dummy, sql_statement, _, DBPrio_High);
|
|
}
|
|
delete results;
|
|
char ip_subblock[8][8];
|
|
ExplodeString(s_client_ip, ".", ip_subblock, sizeof(ip_subblock), sizeof(ip_subblock[]));
|
|
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' and cr1.ipv4 like '%s.%s.%s' limit 1", s_client_ip, ip_subblock[0], ip_subblock[1], "%");
|
|
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[1024];
|
|
char sql_statement_query[512];
|
|
Format(sql_statement_query, sizeof(sql_statement_query), "update connect_restriction set cooldown = DATE_ADD(now(), INTERVAL 170 DAY) where steam_id = '%s' and ipv4 = '%s'", sAuthID, s_client_ip);
|
|
Format(sql_statement, sizeof(sql_statement), "update connect_restriction set cooldown = DATE_ADD(now(), INTERVAL 170 DAY), cooldown_query = %s%s%s where steam_id = '%s' and ipv4 = '%s'", "\"", sql_statement_query, "\"", sAuthID, s_client_ip);
|
|
g_hDatabase.Query(sql_insert_dummy, sql_statement, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
public void sql_select_if_exists(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 sAddress[16];
|
|
GetClientIP(client, sAddress, sizeof(sAddress));
|
|
if (results.RowCount && results.FetchRow())
|
|
{
|
|
char sql_statement[1024];
|
|
char s_country[64];
|
|
char s_asn[512];
|
|
char s_provider[64];
|
|
char s_steam[64];
|
|
char s_ipv4[64];
|
|
results.FetchString(0, s_country, sizeof(s_country));
|
|
results.FetchString(1, s_asn, sizeof(s_asn));
|
|
results.FetchString(2, s_provider, sizeof(s_provider));
|
|
results.FetchString(4, s_steam, sizeof(s_steam));
|
|
results.FetchString(5, s_ipv4, sizeof(s_ipv4));
|
|
Format(g_asn[client], sizeof(g_asn[]), s_asn);
|
|
g_hDatabase.Escape(s_provider, g_provider[client], sizeof(g_provider[]));
|
|
Format(g_country[client], sizeof(g_country[]), s_country);
|
|
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()", s_country, s_asn, s_provider, s_steam, s_ipv4);
|
|
g_hDatabase.Query(SQL_insert, sql_statement, GetClientSerial(client), DBPrio_High);
|
|
//we already have the infos on the IP address so we skip the https request
|
|
}
|
|
else
|
|
{
|
|
//we have not yet saved infos on the IP so we use the https request
|
|
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;
|
|
}
|
|
}
|
|
delete results;
|
|
}
|
|
|
|
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 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);
|
|
char sIP[32];
|
|
GetClientIP(client, sIP, sizeof(sIP));
|
|
if (!SteamClientAuthenticated(sAuthID))
|
|
{
|
|
char sql_statement[512];
|
|
Format(sql_statement, sizeof(sql_statement), "select * from connect_restriction where steam_id = '%s' and ipv4 = '%s'", sAuthID, sIP);
|
|
g_hDatabase.Query(sql_select_if_exists, sql_statement, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
}
|
|
|
|
stock bool IsValidClient(int client)
|
|
{
|
|
if (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client))
|
|
return true;
|
|
return false;
|
|
}
|
|
|