Merge pull request #1443 from ChillerDragon/AutobanKnownBots

Add autoban depending on client version
This commit is contained in:
Dennis Felsing 2019-02-13 12:04:51 +01:00 committed by GitHub
commit 698a3f1c5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 144 additions and 20 deletions

View file

@ -3041,6 +3041,50 @@ unsigned str_quickhash(const char *str)
return hash;
}
static const char *str_token_next(const char *str, const char *delim, size_t *length)
{
str += strspn(str, delim);
if(!*str)
return NULL;
*length = strcspn(str, delim);
return str;
}
int str_tokenize(const char *str, const char *delim, const char **state, char *buf, size_t bufsz)
{
const char *ret = NULL;
size_t len = 0;
if((!str && !state) || !buf)
return -1;
str = str ? str : *state;
if(!(ret = str_token_next(str, delim, &len)))
return -1;
*state = ret + len;
len = bufsz > len ? len : bufsz - 1;
mem_copy(buf, ret, len);
buf[len] = '\0';
return len;
}
int str_in_list(const char *list, const char *delim, const char *needle)
{
const char *tok = list;
size_t len = 0, notfound = 1;
while(notfound && (tok = str_token_next(tok, delim, &len))){
notfound = str_comp_num(tok, needle, len);
tok = tok + len;
}
return !notfound;
}
int pid()
{
#if defined(CONF_FAMILY_WINDOWS)

View file

@ -1831,6 +1831,40 @@ int str_utf16le_encode(char *ptr, int chr);
*/
int str_utf8_check(const char *str);
/*
Function: str_tokenize
Tokenizes a string.
Parameters:
str - Pointer to string.
delim - Delimiter for tokenization.
state - Pointer to remaining string
buf - Buffer to store token in.
bufsz - Size of the buffer.
Returns:
The number of characters written to buf or -1 for end of string
Remarks:
- The token is always null-terminated.
*/
int str_tokenize(const char *str, const char *delim, const char **state, char *buf, size_t bufsz);
/*
Function: str_in_list
Checks if needle is in list delimited by delim
Parameters:
list - List
delim - List delimiter.
needle - Item that is being looked for.
Returns:
1 - Item is in list.
0 - Item isn't in list.
*/
int str_in_list(const char *list, const char *delim, const char *needle);
int pid();
/*

View file

@ -167,6 +167,8 @@ public:
virtual int GetAuthedState(int ClientID) = 0;
virtual const char *GetAuthName(int ClientID) = 0;
virtual void Kick(int ClientID, const char *pReason) = 0;
virtual void Ban(int ClientID, int Seconds, const char *pReason) = 0;
virtual void DemoRecorder_HandleAutoStart() = 0;
virtual bool DemoRecorder_IsRecording() = 0;

View file

@ -428,6 +428,13 @@ void CServer::Kick(int ClientID, const char *pReason)
m_NetServer.Drop(ClientID, pReason);
}
void CServer::Ban(int ClientID, int Seconds, const char *pReason)
{
NETADDR Addr;
GetClientAddr(ClientID, &Addr);
m_NetServer.NetBan()->BanAddr(&Addr, Seconds, pReason);
}
/*int CServer::Tick()
{
return m_CurrentGameTick;

View file

@ -238,6 +238,7 @@ public:
virtual void SetClientScore(int ClientID, int Score);
void Kick(int ClientID, const char *pReason);
void Ban(int ClientID, int Seconds, const char *pReason);
void DemoRecorder_HandleAutoStart();
bool DemoRecorder_IsRecording();

View file

@ -359,6 +359,7 @@ MACRO_CONFIG_INT(SvSoloServer, sv_solo_server, 0, 0, 1, CFGFLAG_SERVER|CFGFLAG_G
MACRO_CONFIG_STR(SvClientSuggestion, sv_client_suggestion, 128, "Get DDNet client from DDNet.tw to use all features on DDNet!", CFGFLAG_SERVER, "Broadcast to display to players without DDNet client")
MACRO_CONFIG_STR(SvClientSuggestionOld, sv_client_suggestion_old, 128, "Your DDNet client is old, update it on DDNet.tw!", CFGFLAG_SERVER, "Broadcast to display to players with an old version of DDNet client")
MACRO_CONFIG_STR(SvClientSuggestionBot, sv_client_suggestion_bot, 128, "Your client has bots and can be remotely controlled!\nPlease use another client like DDNet client from DDNet.tw", CFGFLAG_SERVER, "Broadcast to display to players with a known botting client")
MACRO_CONFIG_STR(SvBannedVersions, sv_banned_versions, 128, "", CFGFLAG_SERVER, "Comma seperated list of banned clients to be kicked on join")
// netlimit
MACRO_CONFIG_INT(SvNetlimit, sv_netlimit, 0, 0, 10000, CFGFLAG_SERVER, "Netlimit: Maximum amount of traffic a client is allowed to use (in kb/s)")

View file

@ -193,7 +193,7 @@ void CGameContext::ConSettings(IConsole::IResult *pResult, void *pUserData)
{
str_format(aBuf, sizeof(aBuf),
"Players are banned for %d minute(s) if they get voted off", g_Config.m_SvVoteKickBantime);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "settings",
g_Config.m_SvVoteKickBantime ?
aBuf :
@ -620,28 +620,19 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
str_copy(aCountry, g_Config.m_SvSqlServerName, sizeof(aCountry));
}
char aValidServerNames[sizeof(g_Config.m_SvSqlValidServerNames)];
str_copy(aValidServerNames, g_Config.m_SvSqlValidServerNames, sizeof(aValidServerNames));
char *p = strtok(aValidServerNames, ",");;
while(p)
if(str_in_list(g_Config.m_SvSqlValidServerNames, ",", aCountry))
{
if(str_comp(p, aCountry) == 0)
{
pSelf->Score()->SaveTeam(Team, pCode, pResult->m_ClientID, aCountry);
pSelf->Score()->SaveTeam(Team, pCode, pResult->m_ClientID, aCountry);
if(g_Config.m_SvUseSQL)
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
return;
}
p = strtok(NULL, ",");
if(g_Config.m_SvUseSQL)
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
}
else
{
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Unknown server name '%s'.", aCountry);
pSelf->SendChatTarget(pResult->m_ClientID, aBuf);
}
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Unknown server name '%s'.", aCountry);
pSelf->SendChatTarget(pResult->m_ClientID, aBuf);
#endif
}

View file

@ -1800,6 +1800,11 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
//tell known bot clients that they're botting and we know it
if (((Version >= 15 && Version < 100) || Version == 502) && g_Config.m_SvClientSuggestionBot[0] != '\0')
SendBroadcast(g_Config.m_SvClientSuggestionBot, ClientID);
//autoban known bot versions
if(g_Config.m_SvBannedVersions[0] != '\0' && IsVersionBanned(Version))
{
Server()->Kick(ClientID, "unsupported client");
}
}
else if (MsgID == NETMSGTYPE_CL_SHOWOTHERS)
{
@ -3550,6 +3555,14 @@ void CGameContext::Converse(int ClientID, char *pStr)
}
}
bool CGameContext::IsVersionBanned(int Version)
{
char aVersion[16];
str_format(aVersion, sizeof(aVersion), "%d", Version);
return str_in_list(g_Config.m_SvBannedVersions, ",", aVersion);
}
void CGameContext::List(int ClientID, const char *pFilter)
{
int Total = 0;

View file

@ -389,6 +389,7 @@ private:
void Whisper(int ClientID, char *pStr);
void WhisperID(int ClientID, int VictimID, char *pMessage);
void Converse(int ClientID, char *pStr);
bool IsVersionBanned(int Version);
public:
CLayers *Layers() { return &m_Layers; }

View file

@ -135,3 +135,33 @@ TEST(Str, HexDecode)
EXPECT_EQ(str_hex_decode(aOut, 1, "411"), 2); EXPECT_STREQ(aOut + 1, "bcd");
EXPECT_EQ(str_hex_decode(aOut, 4, "41424344"), 0); EXPECT_STREQ(aOut, "ABCD");
}
TEST(Str, Tokenize)
{
char aTest[] = "GER,RUS,ZAF,BRA,CAN";
const char *aOut[] = {"GER", "RUS", "ZAF", "BRA", "CAN"};
const char *pState;
char aBuf[4];
int n = 0;
str_tokenize(aTest, ",", &pState, aBuf, sizeof aBuf);
do {
EXPECT_STREQ(aOut[n++], aBuf);
} while(str_tokenize(NULL, ",", &pState, aBuf, sizeof aBuf) >= 0);
char aTest2[] = "";
EXPECT_EQ(str_tokenize(aTest2, ",", &pState, aBuf, sizeof aBuf), -1);
}
TEST(Str, InList)
{
char aTest[] = "GER,RUS,ZAF,BRA,CAN";
EXPECT_TRUE(str_in_list(aTest, ",", "GER"));
EXPECT_TRUE(str_in_list(aTest, ",", "RUS"));
EXPECT_TRUE(str_in_list(aTest, ",", "ZAF"));
EXPECT_TRUE(str_in_list(aTest, ",", "BRA"));
EXPECT_TRUE(str_in_list(aTest, ",", "CAN"));
EXPECT_FALSE(str_in_list(aTest, ",", "CHN"));
EXPECT_FALSE(str_in_list(aTest, ",", "R,R"));
}