diff options
author | thilo <thilo@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2008-04-12 17:00:18 +0000 |
---|---|---|
committer | thilo <thilo@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2008-04-12 17:00:18 +0000 |
commit | 2f4b09a3fd677b7fb66723bd64358dd0798a2af5 (patch) | |
tree | dbbaa32ed2043db251064baacb700ffc973b7fa3 /code/server | |
parent | a957b652bae5d1a5320eb01c349437bc7197b91a (diff) | |
download | ioquake3-aero-2f4b09a3fd677b7fb66723bd64358dd0798a2af5.tar.gz ioquake3-aero-2f4b09a3fd677b7fb66723bd64358dd0798a2af5.zip |
- fix a potential file descriptor leak in server side of pak downloading
- add new functions for banning clients from server, in engine part. This will also make it possible to ban ipv6 addresses in old mods.
git-svn-id: svn://svn.icculus.org/quake3/trunk@1312 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/server')
-rw-r--r-- | code/server/server.h | 15 | ||||
-rw-r--r-- | code/server/sv_ccmds.c | 335 | ||||
-rw-r--r-- | code/server/sv_client.c | 95 | ||||
-rw-r--r-- | code/server/sv_init.c | 3 | ||||
-rw-r--r-- | code/server/sv_main.c | 3 |
5 files changed, 450 insertions, 1 deletions
diff --git a/code/server/server.h b/code/server/server.h index 6a7612b..3d03aee 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -213,6 +213,18 @@ typedef struct { netadr_t authorizeAddress; // for rcon return messages } serverStatic_t; +#define SERVER_MAXBANS 1024 +#define SERVER_BANFILE "serverbans.dat" +// Structure for managing bans +typedef struct +{ + netadr_t ip; + // For a CIDR-Notation type suffix + int subnet; + + qboolean isexception; +} serverBan_t; + //============================================================================= extern serverStatic_t svs; // persistant server info across maps @@ -249,6 +261,9 @@ extern cvar_t *sv_floodProtect; extern cvar_t *sv_lanForceRate; extern cvar_t *sv_strictAuth; +extern serverBan_t serverBans[SERVER_MAXBANS]; +extern int serverBansCount; + //=========================================================== // diff --git a/code/server/sv_ccmds.c b/code/server/sv_ccmds.c index e2bcd93..ad49334 100644 --- a/code/server/sv_ccmds.c +++ b/code/server/sv_ccmds.c @@ -513,6 +513,333 @@ static void SV_BanNum_f( void ) { /* ================== +SV_RehashBans_f + +Load saved bans from file. +================== +*/ +void SV_RehashBans_f(void) +{ + int index, filelen; + fileHandle_t readfrom; + char *textbuf, *curpos, *maskpos, *newlinepos, *endpos; + char filepath[MAX_QPATH]; + + serverBansCount = 0; + + if(!(curpos = Cvar_VariableString("fs_game")) || !*curpos) + curpos = BASEGAME; + + Com_sprintf(filepath, sizeof(filepath), "%s/%s", curpos, SERVER_BANFILE); + + if((filelen = FS_SV_FOpenFileRead(filepath, &readfrom)) >= 0) + { + if(filelen < 2) + { + // Don't bother if file is too short. + FS_FCloseFile(readfrom); + return; + } + + curpos = textbuf = Z_Malloc(filelen); + + filelen = FS_Read(textbuf, filelen, readfrom); + FS_FCloseFile(readfrom); + + endpos = textbuf + filelen; + + for(index = 0; index < SERVER_MAXBANS && curpos + 2 < endpos; index++) + { + // find the end of the address string + for(maskpos = curpos + 2; maskpos < endpos && *maskpos != ' '; maskpos++); + + if(maskpos + 1 >= endpos) + break; + + *maskpos = '\0'; + maskpos++; + + // find the end of the subnet specifier + for(newlinepos = maskpos; newlinepos < endpos && *newlinepos != '\n'; newlinepos++); + + if(newlinepos >= endpos) + break; + + *newlinepos = '\0'; + + if(NET_StringToAdr(curpos + 2, &serverBans[index].ip, NA_UNSPEC)) + { + serverBans[index].isexception = !(curpos[0] == '0'); + serverBans[index].subnet = atoi(maskpos); + + if(serverBans[index].ip.type == NA_IP && + (serverBans[index].subnet < 0 || serverBans[index].subnet > 32)) + { + serverBans[index].subnet = 32; + } + else if(serverBans[index].ip.type == NA_IP6 && + (serverBans[index].subnet < 0 || serverBans[index].subnet > 128)) + { + serverBans[index].subnet = 128; + } + } + + curpos = newlinepos + 1; + } + + serverBansCount = index; + + Z_Free(textbuf); + } +} + +/* +================== +SV_BanAddr_f + +Ban a user from being able to play on this server based on his ip address. +================== +*/ + +static void SV_AddBanToList(qboolean isexception) +{ + char *banstring, *suffix; + netadr_t ip; + int argc, mask; + fileHandle_t writeto; + + argc = Cmd_Argc(); + + if(argc < 2 || argc > 3) + { + Com_Printf ("Usage: %s (ip[/subnet] | clientnum [subnet])\n", Cmd_Argv(0)); + return; + } + + if(serverBansCount > sizeof(serverBans) / sizeof(*serverBans)) + { + Com_Printf ("Error: Maximum number of bans/exceptions exceeded.\n"); + return; + } + + banstring = Cmd_Argv(1); + + if(strchr(banstring, '.') || strchr(banstring, ':')) + { + // This is an ip address, not a client num. + + // Look for a CIDR-Notation suffix + suffix = strchr(banstring, '/'); + if(suffix) + { + *suffix = '\0'; + suffix++; + } + + if(!NET_StringToAdr(banstring, &ip, NA_UNSPEC)) + { + Com_Printf("Error: Invalid address %s\n", banstring); + return; + } + } + else + { + client_t *cl; + + // client num. + if(!com_sv_running->integer) + { + Com_Printf("Server is not running.\n"); + return; + } + + cl = SV_GetPlayerByNum(); + + if(!cl) + { + Com_Printf("Error: Playernum %s does not exist.\n", Cmd_Argv(1)); + return; + } + + ip = cl->netchan.remoteAddress; + + if(argc == 3) + suffix = Cmd_Argv(2); + else + suffix = NULL; + } + + if(ip.type != NA_IP && ip.type != NA_IP6) + { + Com_Printf("Error: Can ban players connected via the internet only.\n"); + return; + } + + if(suffix) + { + mask = atoi(suffix); + + if(ip.type == NA_IP) + { + if(mask < 0 || mask > 32) + mask = 32; + } + else + { + if(mask < 0 || mask > 128) + mask = 128; + } + } + else if(ip.type == NA_IP) + mask = 32; + else + mask = 128; + + serverBans[serverBansCount].ip = ip; + serverBans[serverBansCount].subnet = mask; + serverBans[serverBansCount].isexception = isexception; + + Com_Printf("Added %s: %s/%d\n", isexception ? "ban exception" : "ban", + NET_AdrToString(ip), mask); + + // Write out the ban information. + if((writeto = FS_FOpenFileAppend(SERVER_BANFILE))) + { + char writebuf[128]; + + Com_sprintf(writebuf, sizeof(writebuf), "%d %s %d\n", isexception, NET_AdrToString(ip), mask); + FS_Write(writebuf, strlen(writebuf), writeto); + FS_FCloseFile(writeto); + } + + serverBansCount++; +} + +static void SV_DelBanFromList(qboolean isexception) +{ + int index, count, todel; + fileHandle_t writeto; + + if(Cmd_Argc() != 2) + { + Com_Printf ("Usage: %s <num>\n", Cmd_Argv(0)); + return; + } + + todel = atoi(Cmd_Argv(1)); + + if(todel < 0 || todel > serverBansCount) + return; + + for(index = count = 0; index < serverBansCount; index++) + { + if(serverBans[index].isexception == isexception) + { + count++; + + if(count == todel) + break; + } + } + + if(index == serverBansCount - 1) + serverBansCount--; + else if(index < sizeof(serverBans) / sizeof(*serverBans) - 1) + { + memmove(serverBans + index, serverBans + index + 1, (serverBansCount - index - 1) * sizeof(*serverBans)); + serverBansCount--; + } + else + { + Com_Printf("Error: No such entry #%d\n", todel); + return; + } + + // Write out the ban information. + if((writeto = FS_FOpenFileWrite(SERVER_BANFILE))) + { + char writebuf[128]; + serverBan_t *curban; + + for(index = 0; index < serverBansCount; index++) + { + curban = &serverBans[index]; + + Com_sprintf(writebuf, sizeof(writebuf), "%d %s %d\n", + curban->isexception, NET_AdrToString(curban->ip), curban->subnet); + FS_Write(writebuf, strlen(writebuf), writeto); + } + + FS_FCloseFile(writeto); + } +} + +static void SV_ListBans_f(void) +{ + int index, count; + serverBan_t *ban; + + // List all bans + for(index = count = 0; index < serverBansCount; index++) + { + ban = &serverBans[index]; + if(!ban->isexception) + { + count++; + + Com_Printf("Ban #%d: %s/%d\n", count, + NET_AdrToString(ban->ip), ban->subnet); + } + } + // List all exceptions + for(index = count = 0; index < serverBansCount; index++) + { + ban = &serverBans[index]; + if(ban->isexception) + { + count++; + + Com_Printf("Except #%d: %s/%d\n", count, + NET_AdrToString(ban->ip), ban->subnet); + } + } +} + +static void SV_FlushBans_f(void) +{ + fileHandle_t blankf; + + serverBansCount = 0; + + // empty the ban file. + blankf = FS_FOpenFileWrite(SERVER_BANFILE); + + if(blankf) + FS_FCloseFile(blankf); +} + +static void SV_BanAddr_f(void) +{ + SV_AddBanToList(qfalse); +} + +static void SV_ExceptAddr_f(void) +{ + SV_AddBanToList(qtrue); +} + +static void SV_BanDel_f(void) +{ + SV_DelBanFromList(qfalse); +} + +static void SV_ExceptDel_f(void) +{ + SV_DelBanFromList(qtrue); +} + +/* +================== SV_KickNum_f Kick a user off of the server FIXME: move to game @@ -763,6 +1090,14 @@ void SV_AddOperatorCommands( void ) { if( com_dedicated->integer ) { Cmd_AddCommand ("say", SV_ConSay_f); } + + Cmd_AddCommand("rehashbans", SV_RehashBans_f); + Cmd_AddCommand("listbans", SV_ListBans_f); + Cmd_AddCommand("banaddr", SV_BanAddr_f); + Cmd_AddCommand("exceptaddr", SV_ExceptAddr_f); + Cmd_AddCommand("bandel", SV_BanDel_f); + Cmd_AddCommand("exceptdel", SV_ExceptDel_f); + Cmd_AddCommand("flushbans", SV_FlushBans_f); } /* diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 8230036..eced3d9 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -235,6 +235,86 @@ A "connect" OOB command has been received ================== */ +qboolean SV_IsBanned(netadr_t *from, qboolean isexception) +{ + int index, addrlen, curbyte, netmask, cmpmask; + serverBan_t *curban; + byte *addrfrom, *addrban; + qboolean differed; + + if(from->type == NA_IP) + addrlen = sizeof(from->ip); + else if(from->type == NA_IP6) + addrlen = sizeof(from->ip6); + else + return qfalse; + + if(!isexception) + { + // If this is a query for a ban, first check whether the client is excepted + if(SV_IsBanned(from, qtrue)) + return qfalse; + } + + for(index = 0; index < serverBansCount; index++) + { + curban = &serverBans[index]; + + if(curban->isexception == isexception && from->type == curban->ip.type) + { + if(from->type == NA_IP) + { + addrfrom = from->ip; + addrban = curban->ip.ip; + } + else + { + addrfrom = from->ip6; + addrban = curban->ip.ip6; + } + + differed = qfalse; + curbyte = 0; + + for(netmask = curban->subnet; netmask > 7; netmask -= 8) + { + if(addrfrom[curbyte] != addrban[curbyte]) + { + differed = qtrue; + break; + } + + curbyte++; + } + + if(differed) + continue; + + if(netmask) + { + cmpmask = (1 << netmask) - 1; + cmpmask <<= 8 - netmask; + + if((addrfrom[curbyte] & cmpmask) == (addrban[curbyte] & cmpmask)) + return qtrue; + } + else + return qtrue; + + } + } + + return qfalse; +} + +/* +================== +SV_DirectConnect + +A "connect" OOB command has been received +================== +*/ + void SV_DirectConnect( netadr_t from ) { char userinfo[MAX_INFO_STRING]; int i; @@ -252,6 +332,13 @@ void SV_DirectConnect( netadr_t from ) { char *ip; Com_DPrintf ("SVC_DirectConnect ()\n"); + + // Check whether this client is banned. + if(SV_IsBanned(&from, qfalse)) + { + NET_OutOfBandPrint(NS_SERVER, from, "print\nYou are banned from this server.\n"); + return; + } Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); @@ -821,11 +908,13 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) } } + cl->download = 0; + // We open the file here if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) || idPack || unreferenced || - ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { + ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { @@ -868,6 +957,10 @@ void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; + + if(cl->download) + FS_FCloseFile(cl->download); + return; } diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 3b9cf3d..aca7691 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -687,6 +687,9 @@ void SV_Init (void) { // init the botlib here because we need the pre-compiler in the UI SV_BotInitBotLib(); + + // Load saved bans + Cbuf_AddText("rehashbans\n"); } diff --git a/code/server/sv_main.c b/code/server/sv_main.c index 96a6515..552c12b 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -54,6 +54,9 @@ cvar_t *sv_floodProtect; cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491) cvar_t *sv_strictAuth; +serverBan_t serverBans[SERVER_MAXBANS]; +int serverBansCount = 0; + /* ============================================================================= |