//----------------------------------------------------------------------------- // // $Logfile:: /Code/DLLs/game/ipfilter.cpp $ // $Revision:: 5 $ // $Date:: 12/19/02 7:06p $ // // Copyright (C) 1999 by Ritual Entertainment, Inc. // All rights reserved. // // This source is may not be distributed and/or modified without // expressly written permission by Ritual Entertainment, Inc. // // // DESCRIPTION: // PACKET FILTERING // // You can add or remove addresses from the filter list with: // // addip // removeip // // The ip address is specified in dot format, and any unspecified digits will match // any value, so you can specify an entire class C network with "addip 192.246.40". // // Removeip will only remove an address specified exactly the same way. You cannot // addip a subnet, then removeip a single host. // // listip // Prints the current list of filters. // // writeip // Dumps "addip " commands to listip.cfg so it can be execed at a later date. // The filter lists are not saved and restored by default, because I beleive it would // cause too much confusion. // // filterban <0 or 1> // // If 1 (the default), then ip addresses matching the current list will be prohibited // from entering the game. This is the default setting. // // If 0, then only addresses matching the list will be allowed. This lets you easily // set up a private game, or a game that only allows players from your local network. // #include "_pch_cpp.h" #include "ipfilter.h" typedef struct { unsigned mask; unsigned compare; } ipfilter_t; #define MAX_IPFILTERS 1024 ipfilter_t ipfilters[ MAX_IPFILTERS ]; int numipfilters; /* ================= StringToFilter ================= */ static qboolean StringToFilter( const char *s, ipfilter_t *f ) { char num[ 128 ]; int i; int j; byte b[ 4 ]; byte m[ 4 ]; for( i = 0; i < 4; i++ ) { b[ i ] = 0; m[ i ] = 0; } for( i = 0; i < 4; i++ ) { if ( ( *s < '0' ) || ( *s > '9' ) ) { gi.SendServerCommand( NULL, "print \"Bad filter address: %s\n\"", s ); return false; } j = 0; while( ( *s >= '0' ) && ( *s <= '9' ) ) { num[ j++ ] = *s++; } num[ j ] = 0; b[ i ] = atoi( num ); if ( b[ i ] != 0 ) { m[ i ] = 255; } if ( !*s ) { break; } s++; } f->mask = *( unsigned * )m; f->compare = *( unsigned * )b; return true; } /* ================= SV_FilterPacket ================= */ qboolean SV_FilterPacket( const char *from ) { int i; unsigned in; byte m[ 4 ]; const char *p; if ( !from ) return false; i = 0; p = from; while( *p && ( i < 4 ) ) { m[ i ] = 0; while( ( *p >= '0' ) && ( *p <= '9' ) ) { m[ i ] = m[ i ] * 10 + ( *p - '0' ); p++; } if ( !*p || ( *p == ':' ) ) { break; } i++; p++; } in = *( unsigned * )m; for( i = 0; i < numipfilters; i++ ) { if ( ( in & ipfilters[ i ].mask ) == ipfilters[ i ].compare ) { return ( int )filterban->integer; } } return !( int )filterban->integer; } /* ================= SV_AddIP_f ================= */ void SVCmd_AddIP_f( void ) { int i; if ( gi.argc() < 3 ) { gi.SendServerCommand( NULL, "print \"Usage: addip \n\"" ); return; } for( i = 0; i < numipfilters; i++ ) { if ( ipfilters[ i ].compare == 0xffffffff ) { // free spot break; } } if ( i == numipfilters ) { if ( numipfilters == MAX_IPFILTERS ) { gi.SendServerCommand( NULL, "print \"IP filter list is full\n\"" ); return; } numipfilters++; } if ( !StringToFilter( gi.argv( 2 ), &ipfilters[ i ] ) ) { ipfilters[ i ].compare = 0xffffffff; } } /* ================= SV_RemoveIP_f ================= */ void SVCmd_RemoveIP_f( void ) { ipfilter_t f; int i; int j; if ( gi.argc() < 3 ) { gi.SendServerCommand( NULL, "print \"Usage: sv removeip \n\"" ); return; } if ( !StringToFilter( gi.argv( 2 ), &f ) ) { return; } for( i = 0; i < numipfilters; i++ ) { if ( ( ipfilters[ i ].mask == f.mask ) && ( ipfilters[ i ].compare == f.compare ) ) { for ( j = i + 1; j < numipfilters; j++ ) { ipfilters[ j - 1 ] = ipfilters[ j ]; } numipfilters--; gi.SendServerCommand( NULL, "print \"Removed.\n\"" ); return; } } gi.SendServerCommand( NULL, "print \"Didn't find %s.\n\"", gi.argv( 2 ) ); } /* ================= SV_ListIP_f ================= */ void SVCmd_ListIP_f( void ) { int i; byte b[ 4 ]; gi.SendServerCommand( NULL, "print \"Filter list:\n\"", gi.argv( 2 ) ); for( i = 0; i < numipfilters; i++ ) { *( unsigned * )b = ipfilters[ i ].compare; gi.SendServerCommand( NULL, "print \"%3i.%3i.%3i.%3i\n\"", b[ 0 ], b[ 1 ], b[ 2 ], b[ 3 ] ); } } /* ================= SV_WriteIP_f ================= */ void SVCmd_WriteIP_f( void ) { FILE *f; char name[ MAX_OSPATH ]; byte b[ 4 ]; int i; sprintf( name, "%s/listip.cfg", GAME_NAME ); gi.SendServerCommand( NULL, "print \"Writing %s.\n\"", name ); f = fopen( name, "wb" ); if ( !f ) { gi.SendServerCommand( NULL, "print \"Couldn't open %s.\n\"", name ); return; } fprintf( f, "set filterban %d\n", ( int )filterban->integer ); for( i = 0; i < numipfilters; i++ ) { *( unsigned * )b = ipfilters[ i ].compare; fprintf( f, "sv addip %i.%i.%i.%i\n", b[ 0 ], b[ 1 ], b[ 2 ], b[ 3 ] ); } fclose( f ); } /* ================= G_ServerCommand G_ServerCommand will be called when an "sv" command is issued. The game can issue gi.argc() / gi.argv() commands to get the rest of the parameters ================= */ void G_ServerCommand( void ) { const char *cmd; cmd = gi.argv(1); if ( Q_stricmp( cmd, "addip" ) == 0 ) { SVCmd_AddIP_f(); } else if ( Q_stricmp( cmd, "removeip" ) == 0 ) { SVCmd_RemoveIP_f(); } else if ( Q_stricmp( cmd, "listip" ) == 0 ) { SVCmd_ListIP_f(); } else if ( Q_stricmp( cmd, "writeip" ) == 0 ) { SVCmd_WriteIP_f(); } else { gi.SendServerCommand( NULL, "print \"Unknown server command %s.\n\"", cmd ); } }