вторник, 18 сентября 2012 г.

[SourcePawn] Привязка

,
При написании плагина возникает проблема его защиты, дабы исключить массового распространения\перепродажи честного труда. В этой статье мы рассмотрим привязку по ip и порту сервера.

Первый и самый простой способ:Получаем ip серверной переменной hostip
#include 

new String:g_sServerIp[16],
 String:g_sServerPort[8];

public OnPluginStart()
{
 new iIp = GetConVarInt(FindConVar("hostip"));
 GetConVarString(FindConVar("hostport"), g_sServerPort, sizeof(g_sServerPort));
 Format(g_sServerIp, sizeof(g_sServerIp), "%i.%i.%i.%i", (iIp >> 24) & 0x000000FF, (iIp >> 16) & 0x000000FF, (iIp >>  8) & 0x000000FF, iIp & 0x000000FF);
}

public OnConfigsExecuted()
{
 PrintToServer("ip = %s, port = %s", g_sServerIp, g_sServerPort);
}
Данный способ не является универсальным, ведь значение переменной можно изменить.

Второй способ, используя расширение steamtools.
#include 
#include 

new String:g_ServerPort[8],
 String:g_ServerIp[16];

public OnPluginStart()
{
 GetConVarString(FindConVar("hostport"), g_ServerPort, sizeof(g_ServerPort));
}

public OnConfigsExecuted()
{
 new octets[4];
 
 Steam_GetPublicIP(octets);
 Format(g_ServerIp, 16, "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
 PrintToServer("ip = %s, port = %s", g_ServerIp, g_ServerPort);
}
Мы получим значение ip, которое вернет нам steam.

Ну и третий способ, используя php скрипт, tcp соединение и базу MySQL. Для этого нам понадобится расширение socket.
#pragma semicolon 1

#include 
#include 

#define PLUGIN_VERSION  "0.0.1"
#define PLUGIN_NAME  "Protect"

#define SITE    "Ваш сайт"
#define PHP    "protect.php" //Путь до скрипта
#define PHP_GET   "port" // Имя get переменной

#define DEBUG

public Plugin:myinfo = 
{
 name = PLUGIN_NAME,
 author = "duxa",
 description = "",
 version = PLUGIN_VERSION,
 url = ""
}

public OnPluginStart()
{
 new Handle:socket = SocketCreate(SOCKET_TCP, OnSocketError);
 SocketConnect(socket, OnSocketConnected, OnSocketReceive, OnSocketDisconnected, SITE, 80);
}

public OnSocketConnected(Handle:socket, any:arg) 
{
 new String:szServerPort[8],
  String:szRequest[128];
 
 GetConVarString(FindConVar("hostport"), szServerPort, sizeof(szServerPort));
 Format(szRequest, sizeof(szRequest), "GET /%s?%s=%s HTTP/1.0\r\nHost: %s\r\nConnection: close\r\n\r\n", PHP, PHP_GET, szServerPort, SITE);
 SocketSend(socket, szRequest);
}

public OnSocketReceive(Handle:socket, String:receiveData[], const dataSize, any:arg) 
{
 decl String:szTheContent[1024],
    String:szTheNew[1024];
 
 if(dataSize > 0)
    {
  strcopy(szTheContent, sizeof(szTheContent), receiveData);
    
  SplitString(szTheContent, "\r\n\r\n", szTheNew, sizeof(szTheNew));
  ReplaceString(szTheContent, sizeof(szTheContent), szTheNew, "");
  
  if(StrEqual(szTheContent, "\r\n\r\ntrue", false)) //CraZy
  {
   PrintToServer("[%s] Access is allowed!", PLUGIN_NAME);
  } else
  {
   PrintToServer("[%s] Access denied! Contact the author.", PLUGIN_NAME);
  }
 }
}

public OnSocketDisconnected(Handle:socket, any:arg) 
{
 CloseHandle(socket);
 #if defined DEBUG
 PrintToServer("[%s] Socket Disconnected", PLUGIN_NAME);
 #endif
}

public OnSocketError(Handle:socket, const errorType, const errorNum, any:arg) 
{
 PrintToServer("[%s] Socket error %d (errno %d)", PLUGIN_NAME, errorType, errorNum);
 LogError("[%s] Socket error %d (errno %d)", PLUGIN_NAME, errorType, errorNum);
 CloseHandle(socket);
}

Вот собственно и сам php скрипт (protect.php):
*Могут быть погрешности, знания в php невелеки.

<?php
/* Настройки БД */
$host  = "Адрес"; 
$user  = "Логин"; 
$pwd  = "Пароль"; 
/* Настройки БД */

$ip_q  = GetRealIp();

function GetRealIp()
{
 if (!empty($_SERVER['HTTP_CLIENT_IP'])) 
 {
  $ip = $_SERVER['HTTP_CLIENT_IP'];
 } else
 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
 {
  $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
 } else
 {
  $ip = $_SERVER['REMOTE_ADDR'];
 }
 return $ip;
}

if (isset($_GET['port']) && $_GET['port'] > 0)
{
 $port=$_GET['port']; 
} else
{
 echo "false";
 exit();
}

$db = mysql_connect($host,$user,$pwd) or die("Failed to connect to MySQL.");
mysql_select_db("protect",$db) or die("Failed to connect to MySQL.");

$result = mysql_query("SELECT * FROM Protect WHERE ip = '$ip_q' AND port = '$port'");

if (mysql_num_rows($result)>0)
{
 while ($row = mysql_fetch_assoc($result)) echo "true";
} else echo "false";

mysql_close();
?>

Структура таблицы:
CREATE TABLE IF NOT EXISTS `Protect` (
  `id` int(4) NOT NULL,
  `ip` varchar(16) NOT NULL,
  `port` int(6) NOT NULL,
  PRIMARY KEY  (`id`)
);
При запуске плаагина происходит обращение с передачей значения порта сервера (get запрос) и полученные айпи и порт сверяются с теми, что находятся в нашей базе.

Какой из способов использовать решать вам.

1 коммент.: