r1312 - in trunk: . code/client code/qcommon code/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sat Apr 12 13:00:22 EDT 2008


Author: thilo
Date: 2008-04-12 13:00:18 -0400 (Sat, 12 Apr 2008)
New Revision: 1312

Modified:
   trunk/README
   trunk/code/client/cl_main.c
   trunk/code/qcommon/files.c
   trunk/code/qcommon/qcommon.h
   trunk/code/server/server.h
   trunk/code/server/sv_ccmds.c
   trunk/code/server/sv_client.c
   trunk/code/server/sv_init.c
   trunk/code/server/sv_main.c
Log:
- 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.


Modified: trunk/README
===================================================================
--- trunk/README	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/README	2008-04-12 17:00:18 UTC (rev 1312)
@@ -143,11 +143,34 @@
   sv_dlURL                          - the base of the HTTP or FTP site that
                                       holds custom pk3 files for your server
 
+  net_ip6                           - IPv6 address to bind to
+  net_port6                         - port to bind to using the ipv6 address
+  net_enabled                       - enable networking, bitmask. Add up
+                                      number for option to enable it:
+                                      enable ipv4 networking:    1
+                                      enable ipv6 networking:    2
+                                      prioritise ipv6 over ipv4: 4
+                                      disable multicast support: 8
+  net_mcast6addr                    - multicast address to use for scanning for
+                                      ipv6 servers on the local network
+  net_mcastiface                    - outgoing interface to use for scan
+                                      
+
 New commands
   video [filename]        - start video capture (use with demo command)
   stopvideo               - stop video capture
+
   print                   - print out the contents of a cvar
 
+  banaddr <range>         - ban an ip address range from joining a game on this
+                            server, valid <range> is either playernum or CIDR
+                            notation address range.
+  exceptaddr <range>      - exempt an ip address range from a ban.
+  bandel <num>            - delete ban <num>
+  exceptdel <num>         - delete exception <num>
+  listbans                - list all currently active bans and exceptions
+  rehashbans              - reload the banlist from serverbans.dat
+  flushbans               - delete all bans
 
 ------------------------------------------------------------ Miscellaneous -----
 

Modified: trunk/code/client/cl_main.c
===================================================================
--- trunk/code/client/cl_main.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/client/cl_main.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -2784,7 +2784,7 @@
 
 	SCR_Init ();
 
-	Cbuf_Execute ();
+//	Cbuf_Execute ();
 
 	Cvar_Set( "cl_running", "1" );
 

Modified: trunk/code/qcommon/files.c
===================================================================
--- trunk/code/qcommon/files.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/qcommon/files.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -715,7 +715,8 @@
 	if (f) {
 		return FS_filelength(f);
 	}
-	return 0;
+
+	return -1;
 }
 
 

Modified: trunk/code/qcommon/qcommon.h
===================================================================
--- trunk/code/qcommon/qcommon.h	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/qcommon/qcommon.h	2008-04-12 17:00:18 UTC (rev 1312)
@@ -583,6 +583,7 @@
 int		FS_GetModList(  char *listbuf, int bufsize );
 
 fileHandle_t	FS_FOpenFileWrite( const char *qpath );
+fileHandle_t	FS_FOpenFileAppend( const char *filename );
 // will properly create any needed paths and deal with seperater character issues
 
 int		FS_filelength( fileHandle_t f );

Modified: trunk/code/server/server.h
===================================================================
--- trunk/code/server/server.h	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/server/server.h	2008-04-12 17:00:18 UTC (rev 1312)
@@ -213,6 +213,18 @@
 	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_lanForceRate;
 extern	cvar_t	*sv_strictAuth;
 
+extern	serverBan_t serverBans[SERVER_MAXBANS];
+extern	int serverBansCount;
+
 //===========================================================
 
 //

Modified: trunk/code/server/sv_ccmds.c
===================================================================
--- trunk/code/server/sv_ccmds.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/server/sv_ccmds.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -513,6 +513,333 @@
 
 /*
 ==================
+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 @@
 	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);
 }
 
 /*

Modified: trunk/code/server/sv_client.c
===================================================================
--- trunk/code/server/sv_client.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/server/sv_client.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -235,6 +235,86 @@
 ==================
 */
 
+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 @@
 	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 @@
 			}
 		}
 
+		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 @@
 			MSG_WriteString( msg, errorMessage );
 
 			*cl->downloadName = 0;
+			
+			if(cl->download)
+				FS_FCloseFile(cl->download);
+			
 			return;
 		}
  

Modified: trunk/code/server/sv_init.c
===================================================================
--- trunk/code/server/sv_init.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/server/sv_init.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -687,6 +687,9 @@
 
 	// init the botlib here because we need the pre-compiler in the UI
 	SV_BotInitBotLib();
+	
+	// Load saved bans
+	Cbuf_AddText("rehashbans\n");
 }
 
 

Modified: trunk/code/server/sv_main.c
===================================================================
--- trunk/code/server/sv_main.c	2008-04-11 18:39:03 UTC (rev 1311)
+++ trunk/code/server/sv_main.c	2008-04-12 17:00:18 UTC (rev 1312)
@@ -54,6 +54,9 @@
 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;
+
 /*
 =============================================================================
 




More information about the quake3-commits mailing list