2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
7
Quake III Arena source code is free software; you can redistribute it
8
and/or modify it under the terms of the GNU General Public License as
9
published by the Free Software Foundation; either version 2 of the License,
10
or (at your option) any later version.
12
Quake III Arena source code is distributed in the hope that it will be
13
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with Quake III Arena source code; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
===========================================================================
24
// this file holds commands that can be executed by the server console, but not remote clients
30
==============================================================================
35
You can add or remove addresses from the filter list with:
40
The ip address is specified in dot format, and you can use '*' to match any value
41
so you can specify an entire class C network with "addip 192.246.40.*"
43
Removeip will only remove an address specified exactly the same way. You cannot addip a subnet, then removeip a single host.
46
Prints the current list of filters.
50
If 1 (the default), then ip addresses matching the current list will be prohibited from entering the game. This is the default setting.
52
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.
54
TTimo NOTE: for persistence, bans are stored in g_banIPs cvar MAX_CVAR_VALUE_STRING
55
The size of the cvar string buffer is limiting the banning to around 20 masks
56
this could be improved by putting some g_banIPs2 g_banIps3 etc. maybe
57
still, you should rely on PB for banning instead
59
==============================================================================
62
typedef struct ipFilter_s
68
#define MAX_IPFILTERS 1024
70
static ipFilter_t ipFilters[MAX_IPFILTERS];
71
static int numIPFilters;
78
static qboolean StringToFilter (char *s, ipFilter_t *f)
93
if (*s < '0' || *s > '9')
95
if (*s == '*') // 'match any'
104
G_Printf( "Bad filter address: %s\n", s );
109
while (*s >= '0' && *s <= '9')
122
f->mask = *(unsigned *)m;
123
f->compare = *(unsigned *)b;
133
static void UpdateIPBans (void)
138
char iplist_final[MAX_CVAR_VALUE_STRING];
142
for (i = 0 ; i < numIPFilters ; i++)
144
if (ipFilters[i].compare == 0xffffffff)
147
*(unsigned *)b = ipFilters[i].compare;
148
*(unsigned *)m = ipFilters[i].mask;
150
for (j = 0 ; j < 4 ; j++)
153
Q_strcat(ip, sizeof(ip), "*");
155
Q_strcat(ip, sizeof(ip), va("%i", b[j]));
156
Q_strcat(ip, sizeof(ip), (j<3) ? "." : " ");
158
if (strlen(iplist_final)+strlen(ip) < MAX_CVAR_VALUE_STRING)
160
Q_strcat( iplist_final, sizeof(iplist_final), ip);
164
Com_Printf("g_banIPs overflowed at MAX_CVAR_VALUE_STRING\n");
169
trap_Cvar_Set( "g_banIPs", iplist_final );
177
qboolean G_FilterPacket (char *from)
186
while (*p && i < 4) {
188
while (*p >= '0' && *p <= '9') {
189
m[i] = m[i]*10 + (*p - '0');
192
if (!*p || *p == ':')
199
for (i=0 ; i<numIPFilters ; i++)
200
if ( (in & ipFilters[i].mask) == ipFilters[i].compare)
201
return g_filterBan.integer != 0;
203
return g_filterBan.integer == 0;
211
static void AddIP( char *str )
215
for (i = 0 ; i < numIPFilters ; i++)
216
if (ipFilters[i].compare == 0xffffffff)
218
if (i == numIPFilters)
220
if (numIPFilters == MAX_IPFILTERS)
222
G_Printf ("IP filter list is full\n");
228
if (!StringToFilter (str, &ipFilters[i]))
229
ipFilters[i].compare = 0xffffffffu;
239
void G_ProcessIPBans(void)
242
char str[MAX_CVAR_VALUE_STRING];
244
Q_strncpyz( str, g_banIPs.string, sizeof(str) );
246
for (t = s = g_banIPs.string; *t; /* */ ) {
264
void Svcmd_AddIP_f (void)
266
char str[MAX_TOKEN_CHARS];
268
if ( trap_Argc() < 2 ) {
269
G_Printf("Usage: addip <ip-mask>\n");
273
trap_Argv( 1, str, sizeof( str ) );
284
void Svcmd_RemoveIP_f (void)
288
char str[MAX_TOKEN_CHARS];
290
if ( trap_Argc() < 2 ) {
291
G_Printf("Usage: sv removeip <ip-mask>\n");
295
trap_Argv( 1, str, sizeof( str ) );
297
if (!StringToFilter (str, &f))
300
for (i=0 ; i<numIPFilters ; i++) {
301
if (ipFilters[i].mask == f.mask &&
302
ipFilters[i].compare == f.compare) {
303
ipFilters[i].compare = 0xffffffffu;
304
G_Printf ("Removed.\n");
311
G_Printf ( "Didn't find %s.\n", str );
319
void Svcmd_EntityList_f (void) {
323
check = g_entities+1;
324
for (e = 1; e < level.num_entities ; e++, check++) {
325
if ( !check->inuse ) {
329
switch ( check->s.eType ) {
331
G_Printf("ET_GENERAL ");
334
G_Printf("ET_PLAYER ");
337
G_Printf("ET_ITEM ");
340
G_Printf("ET_MISSILE ");
343
G_Printf("ET_MOVER ");
346
G_Printf("ET_BEAM ");
349
G_Printf("ET_PORTAL ");
352
G_Printf("ET_SPEAKER ");
354
case ET_PUSH_TRIGGER:
355
G_Printf("ET_PUSH_TRIGGER ");
357
case ET_TELEPORT_TRIGGER:
358
G_Printf("ET_TELEPORT_TRIGGER ");
361
G_Printf("ET_INVISIBLE ");
364
G_Printf("ET_GRAPPLE ");
367
G_Printf("%3i ", check->s.eType);
371
if ( check->classname ) {
372
G_Printf("%s", check->classname);
378
gclient_t *ClientForString( const char *s ) {
383
// numeric values are just slot numbers
384
if ( s[0] >= '0' && s[0] <= '9' ) {
386
if ( idnum < 0 || idnum >= level.maxclients ) {
387
Com_Printf( "Bad client slot: %i\n", idnum );
391
cl = &level.clients[idnum];
392
if ( cl->pers.connected == CON_DISCONNECTED ) {
393
G_Printf( "Client %i is not connected\n", idnum );
399
// check for a name match
400
for ( i=0 ; i < level.maxclients ; i++ ) {
401
cl = &level.clients[i];
402
if ( cl->pers.connected == CON_DISCONNECTED ) {
405
if ( !Q_stricmp( cl->pers.netname, s ) ) {
410
G_Printf( "User %s is not on the server\n", s );
419
forceteam <player> <team>
422
void Svcmd_ForceTeam_f( void ) {
424
char str[MAX_TOKEN_CHARS];
427
trap_Argv( 1, str, sizeof( str ) );
428
cl = ClientForString( str );
434
trap_Argv( 2, str, sizeof( str ) );
435
SetTeam( &g_entities[cl - level.clients], str );
438
char *ConcatArgs( int start );
446
qboolean ConsoleCommand( void ) {
447
char cmd[MAX_TOKEN_CHARS];
449
trap_Argv( 0, cmd, sizeof( cmd ) );
451
if ( Q_stricmp (cmd, "entitylist") == 0 ) {
452
Svcmd_EntityList_f();
456
if ( Q_stricmp (cmd, "forceteam") == 0 ) {
461
if (Q_stricmp (cmd, "game_memory") == 0) {
466
if (Q_stricmp (cmd, "addbot") == 0) {
471
if (Q_stricmp (cmd, "botlist") == 0) {
476
if (Q_stricmp (cmd, "abort_podium") == 0) {
477
Svcmd_AbortPodium_f();
481
if (Q_stricmp (cmd, "addip") == 0) {
486
if (Q_stricmp (cmd, "removeip") == 0) {
491
if (Q_stricmp (cmd, "listip") == 0) {
492
trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" );
496
if (g_dedicated.integer) {
497
if (Q_stricmp (cmd, "say") == 0) {
498
trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(1) ) );
501
// everything else will also be printed as a say command
502
trap_SendServerCommand( -1, va("print \"server: %s\"", ConcatArgs(0) ) );