/*
 *
 * @name    : DoS-Detect by Z0Rek
 * @author	: Z0Rek
 * @update	: 28.03.2014
 * @site    : WWW.CHEAT-MASTER.RU
 * @version : 0.1 beta
 *
 */

#if defined _dosdetect_included
	#endinput
#endif

#define _dosdetect_included

#define MAX_PING 1200
#define UPDATE_BITRATE 1000
#define MAX_CONNECTIONS_FROM_IP 1
#define MAX_WARNS 3
#define ANTISPAM_TIME 500
#define DISABLE_RCON
#define MAX_FUNCTION_CALL_MS 200
#define MAX_MESSAGES 50
#define CURRENT_CLIENT_VERSION "0.3z"

#define Z0RekFunc[%0] 	forward %0; public %0
#define Kick_(%0) 		SetTimerEx("KickPlayer", 500, false, "d", %0)
#define IsEq(%0,%1) 	!strcmp(%0, %1)

new MessagesCount[MAX_PLAYERS];
new OtherMessages[MAX_PLAYERS];

hook OnGameModeInit()
{
	print(">>> DoS-Detect ");
	print(">>> Open source antiexploit system");
	print(">>> SAMP-SIL.RU");
	print(">>> Version 0.1 beta");
	
	SetTimer("playersTimer", UPDATE_BITRATE, true);
	return 1;
}

hook OnPlayerDeath(playerid, killerid, reason)
{
    SetPVarInt(playerid, "SpawnAllowed_Z0Rek", 1);

	if(playerid == killerid)
	{
	    Kick_(playerid);
	    return 0;
	}

	if(GetTickCount() <= GetPVarInt(playerid, "Flood2"))
	{
		if((GetPVarInt(playerid, "Flood2_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood2_2", (GetPVarInt(playerid, "Flood2_2") + 1));
	}
	SetPVarInt(playerid, "Flood2", (GetTickCount() + MAX_FUNCTION_CALL_MS));
    
    return 1;
}

hook OnPlayerUpdate(playerid)
{
	OtherMessages[playerid]++;
	return 1;
}

hook OnPlayerGiveDamage(playerid, damagedid, Float: amount, weaponid)
{
    OtherMessages[playerid]++;
    return 1;
}

hook OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
	OtherMessages[playerid]++;
	return 1;
}

hook OnPlayerTakeDamage(playerid, issuerid, Float: amount, weaponid)
{
    OtherMessages[playerid]++;
    return 1;
}

hook OnUnoccupiedVehicleUpdate(vehicleid, playerid, passenger_seat)
{
    OtherMessages[playerid]++;
    return 1;
}

hook OnPlayerPickUpPickup(playerid, pickupid)
{
	if(GetTickCount() <= GetPVarInt(playerid, "Flood3"))
	{
		if((GetPVarInt(playerid, "Flood3_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood3_2", (GetPVarInt(playerid, "Flood3_2") + 1));
	}
	SetPVarInt(playerid, "Flood3", (GetTickCount() + MAX_FUNCTION_CALL_MS));

	return 1;
}

hook OnPlayerSelectedMenuRow(playerid, row)
{
	if(GetTickCount() <= GetPVarInt(playerid, "Flood4"))
	{
		if((GetPVarInt(playerid, "Flood4_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood4_2", (GetPVarInt(playerid, "Flood4_2") + 1));
	}
	SetPVarInt(playerid, "Flood4", (GetTickCount() + MAX_FUNCTION_CALL_MS));
	return 1;
}

hook OnPlayerClickPlayer(playerid, clickedplayerid, source)
{
	if(source != 0)
	{
	    Kick_(playerid);
		return 0;
	}
	
	if(GetTickCount() <= GetPVarInt(playerid, "Flood5"))
	{
		if((GetPVarInt(playerid, "Flood5_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood5_2", (GetPVarInt(playerid, "Flood5_2") + 1));
	}
	SetPVarInt(playerid, "Flood5", (GetTickCount() + MAX_FUNCTION_CALL_MS));
	return 1;
}

hook OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
{
	if(GetTickCount() <= GetPVarInt(playerid, "Flood6"))
	{
		if((GetPVarInt(playerid, "Flood6_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood6_2", (GetPVarInt(playerid, "Flood6_2") + 1));
	}
	SetPVarInt(playerid, "Flood6", (GetTickCount() + MAX_FUNCTION_CALL_MS));
	return 1;
}

hook OnPlayerSpawn(playerid)
{
	if(GetPVarInt(playerid, "SpawnAllowed_Z0Rek") != 1)
	{
	    Kick_(playerid);
	}
	SetPVarInt(playerid, "SpawnAllowed_Z0Rek", 0);
	
	return 1;
}

hook OnPlayerConnect(playerid)
{
	SetPVarInt(playerid, "SpawnAllowed_Z0Rek", 0);
	
	new string[17];
    GetPlayerVersion(playerid, string, sizeof(string));
    if(!IsEq(string, CURRENT_CLIENT_VERSION)) Kick_(playerid);
    
    GetPlayerIp(playerid, string, sizeof(string));
	if(GetConnectionsFromIP(string) > MAX_CONNECTIONS_FROM_IP) Kick_(playerid);
	
	OtherMessages[playerid] = 999999999;
	return 1;
}

hook OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
  	if(GetPVarInt(playerid, "Dialog_ID") < 1 || GetPVarInt(playerid, "Dialog_ID") > 32767) return 0;
  	if(GetPVarInt(playerid, "Dialog_ID") != dialogid) return 0;
  	if(strfind(inputtext,"%",true) != -1) return 0;
  	
 	SetPVarInt(playerid, "Dialog_ID", 0);
	return 1;
}

hook OnRconLoginAttempt(ip[], password[], success)
{
	#if defined DISABLE_RCON
	return 0;
	#else
	if(!success)
	{
		new string[64];
		format(string, sizeof(string),"banip %s", ip);
        SendRconCommand(string);
        SendRconCommand("reloadbans");
        printf(">>> С IP %s зафиксирована неудачная попытка входа в RCON. Используемый пароль: %s", ip, password);
        return 0;
	}
	return 1;
	#endif
}

hook OnPlayerRequestClass(playerid, classid)
{
	if(GetTickCount() <= GetPVarInt(playerid, "Flood1"))
	{
		if((GetPVarInt(playerid, "Flood1_2") + 1) >= MAX_WARNS)
		{
			Kick_(playerid);
			return 0;
		}
		SetPVarInt(playerid, "Flood1_2", (GetPVarInt(playerid, "Flood1_2") + 1));
	}
	SetPVarInt(playerid, "Flood1", (GetTickCount() + MAX_FUNCTION_CALL_MS));
	return 1;
}

Z0RekFunc[KickPlayer(playerid)]
{
	Kick(playerid);
}

Z0RekFunc[playersTimer()]
{
	foreach(new i : Player)
	{
	    if(IsPlayerConnected(i))
	    {
			if(GetPlayerPing(i) > MAX_PING || GetPlayerPing(i) < 0)
			{
			    Kick_(i);
			}
    		if(NetStats_MessagesSent(i) - MessagesCount[i] - OtherMessages[i] > MAX_MESSAGES && NetStats_MessagesSent(i) > 2000)
    		{
				Kick_(i);
    		}
    		MessagesCount[i] = NetStats_MessagesSent(i);
    		OtherMessages[i] = 0;
	    }
	}
}

GetConnectionsFromIP(ip[])
{
	new
		connectionscount = 0,
		string[17]
	;
	foreach(new i : Player)
	{
	    GetPlayerIp(i, string, sizeof(string));
	    if(IsEq(ip, string)) connectionscount++;
	}
	return connectionscount;
}

stock SpawnPlayer_Z0Rek(playerid)
{
	SetPVarInt(playerid, "SpawnAllowed_Z0Rek", 1);
	return SpawnPlayer(playerid);
}
#define SpawnPlayer SpawnPlayer_Z0Rek

stock ShowPlayerDialog_Z0Rek(playerid, dialogid, style, caption[], info[], button1[], button2[])
{
	SetPVarInt(playerid, "Dialog_ID", dialogid);
	return ShowPlayerDialog(playerid, dialogid, style, caption, info, button1, button2);
}
#define ShowPlayerDialog ShowPlayerDialog_Z0Rek
