Added banmaster by heinrich5991

This commit is contained in:
GreYFoXGTi 2011-02-07 08:25:38 +02:00
parent e5bff28375
commit d7e4153ec4
11 changed files with 435 additions and 2 deletions

View file

@ -236,6 +236,7 @@ function build(settings)
versionserver = Compile(settings, Collect("src/versionsrv/*.cpp"))
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
banmaster = Compile(settings, Collect("src/banmaster/*.cpp"))
game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source)
game_client = Compile(settings, CollectRecursive("src/game/client/*.cpp"), client_content_source)
game_server = Compile(settings, CollectRecursive("src/game/server/*.cpp"), server_content_source)
@ -276,6 +277,9 @@ function build(settings)
masterserver_exe = Link(server_settings, "mastersrv", masterserver,
engine, zlib)
banmaster_exe = Link(server_settings, "banmaster", banmaster,
engine, zlib)
-- make targets
c = PseudoTarget("client".."_"..settings.config_name, client_exe, client_depends)
if string.find(settings.config_name, "nosql") then
@ -295,9 +299,10 @@ function build(settings)
v = PseudoTarget("versionserver".."_"..settings.config_name, versionserver_exe)
m = PseudoTarget("masterserver".."_"..settings.config_name, masterserver_exe)
b = PseudoTarget("banmaster".."_"..settings.config_name, banmaster_exe)
t = PseudoTarget("tools".."_"..settings.config_name, tools)
all = PseudoTarget(settings.config_name, c, s, v, m, t)
all = PseudoTarget(settings.config_name, c, s, v, m, b, t)
return all
end

2
banmasters.cfg Normal file
View file

@ -0,0 +1,2 @@
clear_banmasters
add_banmaster banmaster.kottnet.net

1
bans.cfg Normal file
View file

@ -0,0 +1 @@
unban_all

View file

@ -64,6 +64,7 @@ shutil.copy("license.txt", package_dir)
shutil.copy("storage.cfg", package_dir)
shutil.copy("announcement.txt", package_dir)
shutil.copy("license_DDRace.txt", package_dir)
shutil.copy("banmasters.cfg", package_dir)
if include_data and not use_bundle:
os.mkdir(os.path.join(package_dir, "data"))

250
src/banmaster/banmaster.cpp Normal file
View file

@ -0,0 +1,250 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/system.h>
#include <engine/shared/network.h>
#include <engine/console.h>
#include <engine/storage.h>
#include "banmaster.h"
enum
{
MAX_BANS=1024,
BAN_REREAD_TIME=300,
CFGFLAG_BANMASTER=1024,
};
static const char BANMASTER_BANFILE[] = "bans.cfg";
struct CBan
{
NETADDR m_Address;
char m_aReason[256];
int64 m_Expire;
};
static CBan m_aBans[MAX_BANS];
static int m_NumBans = 0;
static CNetClient m_Net;
static IConsole *m_pConsole;
static char m_aBindAddr[64] = "";
CBan* CheckBan(NETADDR *pCheck)
{
for(int i = 0; i < m_NumBans; i++)
{
if(pCheck->ip[0] == m_aBans[i].m_Address.ip[0] && pCheck->ip[1] == m_aBans[i].m_Address.ip[1] &&
pCheck->ip[2] == m_aBans[i].m_Address.ip[2] && pCheck->ip[3] == m_aBans[i].m_Address.ip[3])
return &m_aBans[i];
}
return 0;
}
int SendResponse(NETADDR *pAddr, NETADDR *pCheck)
{
static char aIpBan[sizeof(BANMASTER_IPBAN) + 32 + 256] = { 0 };
static char *pIpBanContent = aIpBan + sizeof(BANMASTER_IPBAN);
if (!aIpBan[0])
mem_copy(aIpBan, BANMASTER_IPBAN, sizeof(BANMASTER_IPBAN));
static CNetChunk p;
p.m_ClientID = -1;
p.m_Address = *pAddr;
p.m_Flags = NETSENDFLAG_CONNLESS;
CBan* pBan = CheckBan(pCheck);
if(pBan)
{
str_format(pIpBanContent, 32, "%d.%d.%d.%d", pCheck->ip[0], pCheck->ip[1], pCheck->ip[2], pCheck->ip[3]);
char *pIpBanReason = pIpBanContent + (str_length(pIpBanContent) + 1);
str_copy(pIpBanReason, pBan->m_aReason, 256);
p.m_pData = aIpBan;
p.m_DataSize = sizeof(BANMASTER_IPBAN) + str_length(pIpBanContent) + 1 + str_length(pIpBanReason) + 1;
m_Net.Send(&p);
return 1;
}
else
{
p.m_DataSize = sizeof(BANMASTER_IPOK);
p.m_pData = BANMASTER_IPOK;
m_Net.Send(&p);
return 0;
}
}
void AddBan(NETADDR *pAddr, const char *pReason)
{
CBan *pBan = CheckBan(pAddr);
if(pBan)
{
dbg_msg("banmaster", "updated ban: %d.%d.%d.%d \'%s\' -> \'%s\'",
pAddr->ip[0], pAddr->ip[1], pAddr->ip[2], pAddr->ip[3], pBan->m_aReason, pReason);
str_copy(pBan->m_aReason, pReason, sizeof(m_aBans[m_NumBans].m_aReason));
pBan->m_Expire = -1;
}
else
{
if(m_NumBans == MAX_BANS)
{
dbg_msg("banmaster", "error: banmaster is full");
return;
}
m_aBans[m_NumBans].m_Address = *pAddr;
str_copy(m_aBans[m_NumBans].m_aReason, pReason, sizeof(m_aBans[m_NumBans].m_aReason));
m_aBans[m_NumBans].m_Expire = -1;
dbg_msg("banmaster", "added ban: %d.%d.%d.%d \'%s\'",
pAddr->ip[0], pAddr->ip[1], pAddr->ip[2], pAddr->ip[3], m_aBans[m_NumBans].m_aReason);
m_NumBans++;
}
}
void ClearBans()
{
dbg_msg("banmaster", "cleared bans");
m_NumBans = 0;
}
void PurgeBans()
{
int64 Now = time_get();
int i = 0;
while(i < m_NumBans)
{
if(m_aBans[i].m_Expire != -1 && m_aBans[i].m_Expire < Now)
{
// remove ban
dbg_msg("banmaster", "expired: %d.%d.%d.%d \'%s\'",
m_aBans[i].m_Address.ip[0], m_aBans[i].m_Address.ip[1],
m_aBans[i].m_Address.ip[2], m_aBans[i].m_Address.ip[3], m_aBans[i].m_aReason);
m_aBans[i] = m_aBans[m_NumBans-1];
m_NumBans--;
}
else
i++;
}
}
void ConBan(IConsole::IResult *pResult, void *pUser)
{
NETADDR Addr;
const char *pStr = pResult->GetString(0);
const char *pReason = "";
if(pResult->NumArguments() > 1)
pReason = pResult->GetString(1);
if(!net_addr_from_str(&Addr, pStr))
AddBan(&Addr, pReason);
else
dbg_msg("banmaster", "invalid network address to ban");
}
void ConUnbanAll(IConsole::IResult *pResult, void *pUser)
{
ClearBans();
}
void ConSetBindAddr(IConsole::IResult *pResult, void *pUser)
{
if(m_aBindAddr[0])
return;
str_copy(m_aBindAddr, pResult->GetString(0), sizeof(m_aBindAddr));
dbg_msg("banmaster/network", "bound to %s", m_aBindAddr);
}
void StandardOutput(const char *pLine, void *pUser)
{
}
int main(int argc, const char **argv) // ignore_convention
{
int64 LastUpdate = time_get();
dbg_logger_stdout();
net_init();
IKernel *pKernel = IKernel::Create();
IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); // ignore_convention
m_pConsole = CreateConsole(CFGFLAG_BANMASTER);
m_pConsole->RegisterPrintCallback(StandardOutput, 0);
m_pConsole->Register("ban", "s?r", CFGFLAG_BANMASTER, ConBan, 0, "Bans the specified ip");
m_pConsole->Register("unban_all", "", CFGFLAG_BANMASTER, ConUnbanAll, 0, "Unbans all ips");
m_pConsole->Register("bind", "s", CFGFLAG_BANMASTER, ConSetBindAddr, 0, "Binds to the specified address");
{
bool RegisterFail = false;
RegisterFail = RegisterFail || !pKernel->RegisterInterface(m_pConsole);
RegisterFail = RegisterFail || !pKernel->RegisterInterface(pStorage);
if(RegisterFail)
return -1;
}
m_pConsole->ExecuteFile(BANMASTER_BANFILE);
NETADDR BindAddr;
if(m_aBindAddr[0] && net_host_lookup(m_aBindAddr, &BindAddr, NETTYPE_IPV4) == 0)
{
if(BindAddr.port == 0)
BindAddr.port = BANMASTER_PORT;
}
else
{
mem_zero(&BindAddr, sizeof(BindAddr));
BindAddr.port = BANMASTER_PORT;
}
m_Net.Open(BindAddr, 0);
// TODO: check socket for errors
dbg_msg("banmaster", "started");
while(1)
{
m_Net.Update();
// process m_aPackets
CNetChunk p;
while(m_Net.Recv(&p))
{
if(p.m_DataSize >= sizeof(BANMASTER_IPCHECK) &&
!mem_comp(p.m_pData, BANMASTER_IPCHECK, sizeof(BANMASTER_IPCHECK)))
{
char *pAddr = (char*)p.m_pData + sizeof(BANMASTER_IPCHECK);
NETADDR CheckAddr;
if(net_addr_from_str(&CheckAddr, pAddr))
{
dbg_msg("banmaster", "dropped weird message ip=%d.%d.%d.%d checkaddr='%s'",
p.m_Address.ip[0], p.m_Address.ip[1], p.m_Address.ip[2], p.m_Address.ip[3], pAddr);
}
else
{
int Banned = SendResponse(&p.m_Address, &CheckAddr);
dbg_msg("banmaster", "responded to checkmsg ip=%d.%d.%d.%d checkaddr=%d.%d.%d.%d result=%s",
p.m_Address.ip[0], p.m_Address.ip[1], p.m_Address.ip[2], p.m_Address.ip[3],
CheckAddr.ip[0], CheckAddr.ip[1], CheckAddr.ip[2], CheckAddr.ip[3], (Banned) ? "ban" : "ok");
}
}
}
if(time_get() - LastUpdate > time_freq() * BAN_REREAD_TIME)
{
ClearBans();
LastUpdate = time_get();
m_pConsole->ExecuteFile(BANMASTER_BANFILE);
}
// be nice to the CPU
thread_sleep(1);
}
return 0;
}

12
src/banmaster/banmaster.h Normal file
View file

@ -0,0 +1,12 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef BANMASTER_BANMASTER_H
#define BANMASTER_BANMASTER_H
static const int BANMASTER_PORT = 8302;
static const char BANMASTER_IPOK[] = {255, 255, 255, 255, 'i', 'p', 'o', 'k'};
static const char BANMASTER_IPBAN[] = {255, 255, 255, 255, 'i', 'p', 'b', 'a'};
static const char BANMASTER_IPCHECK[] = {255, 255, 255, 255, 'i', 'p', 'c', 'h'};
#endif

View file

@ -28,6 +28,8 @@
#include <string.h>
#include <banmaster/banmaster.h>
#include "register.h"
#include "server.h"
#include "../shared/linereader.h"
@ -39,6 +41,8 @@
#include <windows.h>
#endif
static const char SERVER_BANMASTERFILE[] = "banmasters.cfg";
static const char *StrLtrim(const char *pStr)
{
while(*pStr && *pStr >= 0 && *pStr <= 32)
@ -1095,6 +1099,33 @@ void CServer::PumpNetwork()
{
SendServerInfo(&Packet.m_Address, -1);
}
if(Packet.m_DataSize >= sizeof(BANMASTER_IPOK) &&
mem_comp(Packet.m_pData, BANMASTER_IPOK, sizeof(BANMASTER_IPOK)) == 0 &&
m_NetServer.BanmasterCheck(&Packet.m_Address) != -1)
{
}
if(Packet.m_DataSize >= sizeof(BANMASTER_IPBAN) &&
mem_comp(Packet.m_pData, BANMASTER_IPBAN, sizeof(BANMASTER_IPBAN)) == 0 &&
g_Config.m_SvGlobalBantime &&
m_NetServer.BanmasterCheck(&Packet.m_Address) != -1)
{
CUnpacker Up;
char aIp[32];
char aReason[256];
NETADDR Addr;
Up.Reset((unsigned char*)Packet.m_pData + sizeof(BANMASTER_IPBAN), Packet.m_DataSize - sizeof(BANMASTER_IPBAN));
str_copy(aIp, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(aIp));
str_copy(aReason, Up.GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(aReason));
if (net_addr_from_str(&Addr, aIp))
{
dbg_msg("globalbans", "dropped weird message from banmaster");
return;
}
m_NetServer.BanAdd(Addr, g_Config.m_SvGlobalBantime * 60, aReason);
dbg_msg("globalbans", "added ban, ip=%d.%d.%d.%d, reason=\"%s\"", Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], aReason);
}
}
}
else
@ -1214,7 +1245,9 @@ int CServer::Run()
}
m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this);
Console()->ExecuteFile(SERVER_BANMASTERFILE);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
@ -1633,6 +1666,10 @@ void CServer::RegisterCommands()
Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "", 3);
Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "", 3);
Console()->Register("add_banmaster", "s", CFGFLAG_SERVER, ConAddBanmaster, this, "", 4);
Console()->Register("banmasters", "", CFGFLAG_SERVER, ConBanmasters, this, "", 3);
Console()->Register("clear_banmasters", "", CFGFLAG_SERVER, ConClearBanmasters, this, "", 4);
Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "", 3);
Console()->Chain("sv_name", ConchainSpecialInfoupdate, this);
@ -1913,3 +1950,42 @@ NETADDR CServer::GetClientIP(int ClientID)//this may exist already but i couldn'
return m_NetServer.ClientAddr(ClientID);
}
void CServer::ConAddBanmaster(IConsole::IResult *pResult, void *pUser, int ClientId)
{
CServer *pServer = (CServer *)pUser;
int Result = pServer->m_NetServer.BanmasterAdd(pResult->GetString(0));
if(Result == 0)
pServer->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "server/banmaster", "succesfully added banmaster");
else if (Result == 1)
pServer->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "server/banmaster", "invalid address for banmaster / net lookup failed");
else
pServer->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "server/banmaster", "too many banmasters");
}
void CServer::ConBanmasters(IConsole::IResult *pResult, void *pUser, int ClientId)
{
CServer *pServer = (CServer *)pUser;
int NumBanmasters = pServer->m_NetServer.BanmasterNum();
char aBuf[128];
char aIpString[64];
for(int i = 0; i < NumBanmasters; i++)
{
NETADDR *pBanmaster = pServer->m_NetServer.BanmasterGet(i);
net_addr_str(pBanmaster, aIpString, sizeof(aIpString));
str_format(aBuf, sizeof(aBuf), "%d: %s", i, aIpString);
pServer->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "server/banmaster", aBuf);
}
}
void CServer::ConClearBanmasters(IConsole::IResult *pResult, void *pUser, int ClientId)
{
CServer *pServer = (CServer *)pUser;
pServer->m_NetServer.BanmastersClear();
}

View file

@ -232,6 +232,9 @@ public:
virtual void SnapFreeID(int ID);
virtual void *SnapNewItem(int Type, int Id, int Size);
void SnapSetStaticsize(int ItemType, int Size);
static void ConAddBanmaster(IConsole::IResult *pResult, void *pUser, int ClientId);
static void ConBanmasters(IConsole::IResult *pResult, void *pUser, int ClientId);
static void ConClearBanmasters(IConsole::IResult *pResult, void *pUser, int ClientId);
};
#endif

View file

@ -199,5 +199,6 @@ MACRO_CONFIG_INT(ClDemoName, cl_demo_name, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE,
MACRO_CONFIG_INT(ClRaceGhost, cl_race_ghost, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Enable ghost",-1)
MACRO_CONFIG_INT(ClRaceShowGhost, cl_race_show_ghost, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show ghost",-1)
MACRO_CONFIG_INT(ClRaceSaveGhost, cl_race_save_ghost, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Save ghost",-1)
MACRO_CONFIG_INT(SvGlobalBantime, sv_global_ban_time, 60, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if the ban server reports it. 0 to disable", 4)
#endif

View file

@ -289,6 +289,20 @@ public:
//
void SetMaxClientsPerIP(int Max);
int BanmasterAdd(const char *pAddrStr);
int BanmasterNum() const;
NETADDR* BanmasterGet(int Index);
int BanmasterCheck(NETADDR *pAddr);
void BanmastersClear();
enum
{
MAX_BANMASTERS=16,
NETSERVER_DISABLEBANMASTER=1,
};
int m_Flags;
NETADDR m_aBanmasters[MAX_BANMASTERS];
int m_NumBanmasters;
};

View file

@ -1,6 +1,7 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/system.h>
#include <banmaster/banmaster.h>
#include "network.h"
#define MACRO_LIST_LINK_FIRST(Object, First, Prev, Next) \
@ -59,6 +60,8 @@ bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int
m_BanPool[NET_SERVER_MAXBANS-1].m_pPrev = &m_BanPool[NET_SERVER_MAXBANS-2];
m_BanPool_FirstFree = &m_BanPool[0];
m_Flags = Flags;
return true;
}
@ -338,6 +341,25 @@ int CNetServer::Recv(CNetChunk *pChunk)
// client that wants to connect
if(!Found)
{
if(!(m_Flags & NETSERVER_DISABLEBANMASTER))
{
CNetChunk Packet;
char aBuffer[64];
mem_copy(aBuffer, BANMASTER_IPCHECK, sizeof(BANMASTER_IPCHECK));
net_addr_str(&Addr, aBuffer + sizeof(BANMASTER_IPCHECK), sizeof(aBuffer) - sizeof(BANMASTER_IPCHECK));
Packet.m_ClientID = -1;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
Packet.m_DataSize = str_length(aBuffer) + 1;
Packet.m_pData = aBuffer;
for(int i = 0; i < m_NumBanmasters; i++)
{
Packet.m_Address = m_aBanmasters[i];
Send(&Packet);
}
}
// only allow a specific number of players with the same ip
NETADDR ThisAddr = Addr, OtherAddr;
int FoundAddr = 1;
@ -369,6 +391,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
if(m_pfnNewClient)
m_pfnNewClient(i, m_UserPtr);
break;
}
}
@ -447,3 +470,48 @@ void CNetServer::SetMaxClientsPerIP(int Max)
m_MaxClientsPerIP = Max;
}
int CNetServer::BanmasterAdd(const char *pAddrStr)
{
if(m_NumBanmasters >= MAX_BANMASTERS)
return 2;
if(net_host_lookup(pAddrStr, &m_aBanmasters[m_NumBanmasters], NETTYPE_IPV4))
return 1;
if(m_aBanmasters[m_NumBanmasters].port == 0)
m_aBanmasters[m_NumBanmasters].port = BANMASTER_PORT;
m_NumBanmasters++;
return 0;
}
int CNetServer::BanmasterNum() const
{
return m_NumBanmasters;
}
NETADDR* CNetServer::BanmasterGet(int Index)
{
if(Index < 0 || Index >= m_NumBanmasters)
return 0;
return &m_aBanmasters[Index];
}
int CNetServer::BanmasterCheck(NETADDR *pAddr)
{
for(int i = 0; i < m_NumBanmasters; i++)
{
if(!net_addr_comp(&m_aBanmasters[i], pAddr))
return i;
}
return -1;
}
void CNetServer::BanmastersClear()
{
m_NumBanmasters = 0;
}