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/sv_ccmds.c | |
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/sv_ccmds.c')
-rw-r--r-- | code/server/sv_ccmds.c | 335 |
1 files changed, 335 insertions, 0 deletions
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); } /* |