1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
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.
11
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.
16
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 ===========================================================================
21 */
22
23 #include "server.h"
24
25 #ifdef USE_VOIP
26 cvar_t *sv_voip;
27 #endif
28
29 serverStatic_t svs; // persistant server info
30 server_t sv; // local server
31 vm_t *gvm = NULL; // game virtual machine
32
33 cvar_t *sv_fps = NULL; // time rate for running non-clients
34 cvar_t *sv_timeout; // seconds without any message
35 cvar_t *sv_zombietime; // seconds to sink messages after disconnect
36 cvar_t *sv_rconPassword; // password for remote server commands
37 cvar_t *sv_privatePassword; // password for the privateClient slots
38 cvar_t *sv_allowDownload;
39 cvar_t *sv_maxclients;
40
41 cvar_t *sv_privateClients; // number of clients reserved for password
42 cvar_t *sv_hostname;
43 cvar_t *sv_master[MAX_MASTER_SERVERS]; // master server ip address
44 cvar_t *sv_reconnectlimit; // minimum seconds between connect messages
45 cvar_t *sv_showloss; // report when usercmds are lost
46 cvar_t *sv_padPackets; // add nop bytes to messages
47 cvar_t *sv_killserver; // menu system can set to 1 to shut server down
48 cvar_t *sv_mapname;
49 cvar_t *sv_mapChecksum;
50 cvar_t *sv_serverid;
51 cvar_t *sv_minRate;
52 cvar_t *sv_maxRate;
53 cvar_t *sv_minPing;
54 cvar_t *sv_maxPing;
55 cvar_t *sv_gametype;
56 cvar_t *sv_dorestart;
57 cvar_t *sv_pure;
58 cvar_t *sv_floodProtect;
59 cvar_t *sv_lanForceRate; // dedicated 1 (LAN) server forces local client rates to 99999 (bug #491)
60 cvar_t *sv_public;
61 cvar_t *sv_banFile;
62 cvar_t *sv_heartbeat; // Heartbeat string that is sent to the master
63 cvar_t *sv_flatline; // If the master server supports it we can send a flatline
64 // when server is killed
65
66 serverBan_t serverBans[SERVER_MAXBANS];
67 int serverBansCount = 0;
68
69 /*
70 =============================================================================
71
72 EVENT MESSAGES
73
74 =============================================================================
75 */
76
77 /*
78 ===============
79 SV_ExpandNewlines
80
81 Converts newlines to "\n" so a line prints nicer
82 ===============
83 */
SV_ExpandNewlines(char * in)84 static char *SV_ExpandNewlines( char *in ) {
85 static char string[1024];
86 int l;
87
88 l = 0;
89 while ( *in && l < sizeof(string) - 3 ) {
90 if ( *in == '\n' ) {
91 string[l++] = '\\';
92 string[l++] = 'n';
93 } else {
94 string[l++] = *in;
95 }
96 in++;
97 }
98 string[l] = 0;
99
100 return string;
101 }
102
103 /*
104 ======================
105 SV_ReplacePendingServerCommands
106
107 FIXME: This is ugly
108 ======================
109 */
110 #if 0 // unused
111 static int SV_ReplacePendingServerCommands( client_t *client, const char *cmd ) {
112 int i, index, csnum1, csnum2;
113
114 for ( i = client->reliableSent+1; i <= client->reliableSequence; i++ ) {
115 index = i & ( MAX_RELIABLE_COMMANDS - 1 );
116 //
117 if ( !Q_strncmp(cmd, client->reliableCommands[ index ], strlen("cs")) ) {
118 sscanf(cmd, "cs %i", &csnum1);
119 sscanf(client->reliableCommands[ index ], "cs %i", &csnum2);
120 if ( csnum1 == csnum2 ) {
121 Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
122 /*
123 if ( client->netchan.remoteAddress.type != NA_BOT ) {
124 Com_Printf( "WARNING: client %i removed double pending config string %i: %s\n", client-svs.clients, csnum1, cmd );
125 }
126 */
127 return qtrue;
128 }
129 }
130 }
131 return qfalse;
132 }
133 #endif
134
135 /*
136 ======================
137 SV_AddServerCommand
138
139 The given command will be transmitted to the client, and is guaranteed to
140 not have future snapshot_t executed before it is executed
141 ======================
142 */
SV_AddServerCommand(client_t * client,const char * cmd)143 void SV_AddServerCommand( client_t *client, const char *cmd ) {
144 int index, i;
145
146 // this is very ugly but it's also a waste to for instance send multiple config string updates
147 // for the same config string index in one snapshot
148 // if ( SV_ReplacePendingServerCommands( client, cmd ) ) {
149 // return;
150 // }
151
152 // do not send commands until the gamestate has been sent
153 if( client->state < CS_PRIMED )
154 return;
155
156 client->reliableSequence++;
157 // if we would be losing an old command that hasn't been acknowledged,
158 // we must drop the connection
159 // we check == instead of >= so a broadcast print added by SV_DropClient()
160 // doesn't cause a recursive drop client
161 if ( client->reliableSequence - client->reliableAcknowledge == MAX_RELIABLE_COMMANDS + 1 ) {
162 Com_Printf( "===== pending server commands =====\n" );
163 for ( i = client->reliableAcknowledge + 1 ; i <= client->reliableSequence ; i++ ) {
164 Com_Printf( "cmd %5d: %s\n", i, client->reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
165 }
166 Com_Printf( "cmd %5d: %s\n", i, cmd );
167 SV_DropClient( client, "Server command overflow" );
168 return;
169 }
170 index = client->reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
171 Q_strncpyz( client->reliableCommands[ index ], cmd, sizeof( client->reliableCommands[ index ] ) );
172 }
173
174
175 /*
176 =================
177 SV_SendServerCommand
178
179 Sends a reliable command string to be interpreted by
180 the client game module: "cp", "print", "chat", etc
181 A NULL client will broadcast to all clients
182 =================
183 */
SV_SendServerCommand(client_t * cl,const char * fmt,...)184 void QDECL SV_SendServerCommand(client_t *cl, const char *fmt, ...) {
185 va_list argptr;
186 byte message[MAX_MSGLEN];
187 client_t *client;
188 int j;
189
190 va_start (argptr,fmt);
191 Q_vsnprintf ((char *)message, sizeof(message), fmt,argptr);
192 va_end (argptr);
193
194 // Fix to http://aluigi.altervista.org/adv/q3msgboom-adv.txt
195 // The actual cause of the bug is probably further downstream
196 // and should maybe be addressed later, but this certainly
197 // fixes the problem for now
198 if ( strlen ((char *)message) > 1022 ) {
199 return;
200 }
201
202 if ( cl != NULL ) {
203 SV_AddServerCommand( cl, (char *)message );
204 return;
205 }
206
207 // hack to echo broadcast prints to console
208 if ( com_dedicated->integer && !strncmp( (char *)message, "print", 5) ) {
209 Com_Printf ("broadcast: %s\n", SV_ExpandNewlines((char *)message) );
210 }
211
212 // send the data to all relevent clients
213 for (j = 0, client = svs.clients; j < sv_maxclients->integer ; j++, client++) {
214 SV_AddServerCommand( client, (char *)message );
215 }
216 }
217
218
219 /*
220 ==============================================================================
221
222 MASTER SERVER FUNCTIONS
223
224 ==============================================================================
225 */
226
227 /*
228 ================
229 SV_MasterHeartbeat
230
231 Send a message to the masters every few minutes to
232 let it know we are alive, and log information.
233 We will also have a heartbeat sent when a server
234 changes from empty to non-empty, and full to non-full,
235 but not on every player enter or exit.
236 ================
237 */
238 #define HEARTBEAT_MSEC 300*1000
SV_MasterHeartbeat(const char * message)239 void SV_MasterHeartbeat(const char *message)
240 {
241 static netadr_t adr[MAX_MASTER_SERVERS][2]; // [2] for v4 and v6 address for the same address string.
242 int i;
243 int res;
244 int netenabled;
245
246 netenabled = Cvar_VariableIntegerValue("net_enabled");
247
248 // "dedicated 1" is for lan play, "dedicated 2" is for inet public play
249 if ( ( (!com_dedicated || com_dedicated->integer != 2) && !(sv_public->integer) ) || !(netenabled & (NET_ENABLEV4 | NET_ENABLEV6)))
250 return; // only dedicated servers send heartbeats
251
252 // if not time yet, don't send anything
253 if ( svs.time < svs.nextHeartbeatTime )
254 return;
255
256 svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC;
257
258 // send to group masters
259 for (i = 0; i < MAX_MASTER_SERVERS; i++)
260 {
261 if(!sv_master[i]->string[0])
262 continue;
263
264 // see if we haven't already resolved the name
265 // resolving usually causes hitches on win95, so only
266 // do it when needed
267 if(sv_master[i]->modified || (adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD))
268 {
269 sv_master[i]->modified = qfalse;
270
271 if(netenabled & NET_ENABLEV4)
272 {
273 Com_Printf("Resolving %s (IPv4)\n", sv_master[i]->string);
274 res = NET_StringToAdr(sv_master[i]->string, &adr[i][0], NA_IP);
275
276 if(res == 2)
277 {
278 // if no port was specified, use the default master port
279 adr[i][0].port = BigShort(PORT_MASTER);
280 }
281
282 if(res)
283 Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][0]));
284 else
285 Com_Printf( "%s has no IPv4 address.\n", sv_master[i]->string);
286 }
287
288 if(netenabled & NET_ENABLEV6)
289 {
290 Com_Printf("Resolving %s (IPv6)\n", sv_master[i]->string);
291 res = NET_StringToAdr(sv_master[i]->string, &adr[i][1], NA_IP6);
292
293 if(res == 2)
294 {
295 // if no port was specified, use the default master port
296 adr[i][1].port = BigShort(PORT_MASTER);
297 }
298
299 if(res)
300 Com_Printf( "%s resolved to %s\n", sv_master[i]->string, NET_AdrToStringwPort(adr[i][1]));
301 else
302 Com_Printf( "%s has no IPv6 address.\n", sv_master[i]->string);
303 }
304
305 if(adr[i][0].type == NA_BAD && adr[i][1].type == NA_BAD)
306 {
307 // if the address failed to resolve, clear it
308 // so we don't take repeated dns hits
309 Com_Printf("Couldn't resolve address: %s\n", sv_master[i]->string);
310 Cvar_Set(sv_master[i]->name, "");
311 sv_master[i]->modified = qfalse;
312 continue;
313 }
314 }
315
316
317 Com_Printf ("Sending heartbeat to %s\n", sv_master[i]->string );
318
319 // this command should be changed if the server info / status format
320 // ever incompatably changes
321
322 if(adr[i][0].type != NA_BAD)
323 NET_OutOfBandPrint( NS_SERVER, adr[i][0], "heartbeat %s\n", message);
324 if(adr[i][1].type != NA_BAD)
325 NET_OutOfBandPrint( NS_SERVER, adr[i][1], "heartbeat %s\n", message);
326 }
327 }
328
329 /*
330 =================
331 SV_MasterShutdown
332
333 Informs all masters that this server is going down
334 =================
335 */
SV_MasterShutdown(void)336 void SV_MasterShutdown( void ) {
337 // send a hearbeat right now
338 svs.nextHeartbeatTime = -9999;
339 SV_MasterHeartbeat(sv_flatline->string);
340
341 // send it again to minimize chance of drops
342 svs.nextHeartbeatTime = -9999;
343 SV_MasterHeartbeat(sv_flatline->string);
344
345 // when the master tries to poll the server, it won't respond, so
346 // it will be removed from the list
347 }
348
349
350 /*
351 ==============================================================================
352
353 CONNECTIONLESS COMMANDS
354
355 ==============================================================================
356 */
357
358 typedef struct leakyBucket_s leakyBucket_t;
359 struct leakyBucket_s {
360 netadrtype_t type;
361
362 union {
363 byte _4[4];
364 byte _6[16];
365 } ipv;
366
367 int lastTime;
368 signed char burst;
369
370 long hash;
371
372 leakyBucket_t *prev, *next;
373 };
374
375 // This is deliberately quite large to make it more of an effort to DoS
376 #define MAX_BUCKETS 16384
377 #define MAX_HASHES 1024
378
379 static leakyBucket_t buckets[ MAX_BUCKETS ];
380 static leakyBucket_t *bucketHashes[ MAX_HASHES ];
381
382 /*
383 ================
384 SVC_HashForAddress
385 ================
386 */
SVC_HashForAddress(netadr_t address)387 static long SVC_HashForAddress( netadr_t address ) {
388 byte *ip = NULL;
389 size_t size = 0;
390 int i;
391 long hash = 0;
392
393 switch ( address.type ) {
394 case NA_IP: ip = address.ip; size = 4; break;
395 case NA_IP6: ip = address.ip6; size = 16; break;
396 default: break;
397 }
398
399 for ( i = 0; i < size; i++ ) {
400 hash += (long)( ip[ i ] ) * ( i + 119 );
401 }
402
403 hash = ( hash ^ ( hash >> 10 ) ^ ( hash >> 20 ) );
404 hash &= ( MAX_HASHES - 1 );
405
406 return hash;
407 }
408
409 /*
410 ================
411 SVC_BucketForAddress
412
413 Find or allocate a bucket for an address
414 ================
415 */
SVC_BucketForAddress(netadr_t address,int burst,int period)416 static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int period ) {
417 leakyBucket_t *bucket = NULL;
418 int i;
419 long hash = SVC_HashForAddress( address );
420 int now = Sys_Milliseconds();
421
422 for ( bucket = bucketHashes[ hash ]; bucket; bucket = bucket->next ) {
423 switch ( bucket->type ) {
424 case NA_IP:
425 if ( memcmp( bucket->ipv._4, address.ip, 4 ) == 0 ) {
426 return bucket;
427 }
428 break;
429
430 case NA_IP6:
431 if ( memcmp( bucket->ipv._6, address.ip6, 16 ) == 0 ) {
432 return bucket;
433 }
434 break;
435
436 default:
437 break;
438 }
439 }
440
441 for ( i = 0; i < MAX_BUCKETS; i++ ) {
442 int interval;
443
444 bucket = &buckets[ i ];
445 interval = now - bucket->lastTime;
446
447 // Reclaim expired buckets
448 if ( bucket->lastTime > 0 && ( interval > ( burst * period ) ||
449 interval < 0 ) ) {
450 if ( bucket->prev != NULL ) {
451 bucket->prev->next = bucket->next;
452 } else {
453 bucketHashes[ bucket->hash ] = bucket->next;
454 }
455
456 if ( bucket->next != NULL ) {
457 bucket->next->prev = bucket->prev;
458 }
459
460 Com_Memset( bucket, 0, sizeof( leakyBucket_t ) );
461 }
462
463 if ( bucket->type == NA_BAD ) {
464 bucket->type = address.type;
465 switch ( address.type ) {
466 case NA_IP: Com_Memcpy( bucket->ipv._4, address.ip, 4 ); break;
467 case NA_IP6: Com_Memcpy( bucket->ipv._6, address.ip6, 16 ); break;
468 default: break;
469 }
470
471 bucket->lastTime = now;
472 bucket->burst = 0;
473 bucket->hash = hash;
474
475 // Add to the head of the relevant hash chain
476 bucket->next = bucketHashes[ hash ];
477 if ( bucketHashes[ hash ] != NULL ) {
478 bucketHashes[ hash ]->prev = bucket;
479 }
480
481 bucket->prev = NULL;
482 bucketHashes[ hash ] = bucket;
483
484 return bucket;
485 }
486 }
487
488 // Couldn't allocate a bucket for this address
489 return NULL;
490 }
491
492 /*
493 ================
494 SVC_RateLimit
495 ================
496 */
SVC_RateLimit(leakyBucket_t * bucket,int burst,int period)497 static qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) {
498 if ( bucket != NULL ) {
499 int now = Sys_Milliseconds();
500 int interval = now - bucket->lastTime;
501 int expired = interval / period;
502 int expiredRemainder = interval % period;
503
504 if ( expired > bucket->burst ) {
505 bucket->burst = 0;
506 bucket->lastTime = now;
507 } else {
508 bucket->burst -= expired;
509 bucket->lastTime = now - expiredRemainder;
510 }
511
512 if ( bucket->burst < burst ) {
513 bucket->burst++;
514
515 return qfalse;
516 }
517 }
518
519 return qtrue;
520 }
521
522 /*
523 ================
524 SVC_RateLimitAddress
525
526 Rate limit for a particular address
527 ================
528 */
SVC_RateLimitAddress(netadr_t from,int burst,int period)529 static qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) {
530 leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period );
531
532 return SVC_RateLimit( bucket, burst, period );
533 }
534
535 /*
536 ================
537 SVC_Status
538
539 Responds with all the info that qplug or qspy can see about the server
540 and all connected players. Used for getting detailed information after
541 the simple info query.
542 ================
543 */
SVC_Status(netadr_t from)544 static void SVC_Status( netadr_t from ) {
545 char player[1024];
546 char status[MAX_MSGLEN];
547 int i;
548 client_t *cl;
549 playerState_t *ps;
550 int statusLength;
551 int playerLength;
552 char infostring[MAX_INFO_STRING];
553 static leakyBucket_t bucket;
554
555 // ignore if we are in single player
556 if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) {
557 return;
558 }
559
560 // Prevent using getstatus as an amplifier
561 if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
562 Com_DPrintf( "SVC_Status: rate limit from %s exceeded, dropping request\n",
563 NET_AdrToString( from ) );
564 return;
565 }
566
567 // Allow getstatus to be DoSed relatively easily, but prevent
568 // excess outbound bandwidth usage when being flooded inbound
569 if ( SVC_RateLimit( &bucket, 10, 100 ) ) {
570 Com_DPrintf( "SVC_Status: rate limit exceeded, dropping request\n" );
571 return;
572 }
573
574 strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO ) );
575
576 // echo back the parameter to status. so master servers can use it as a challenge
577 // to prevent timed spoofed reply packets that add ghost servers
578 Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
579
580 status[0] = 0;
581 statusLength = 0;
582
583 for (i=0 ; i < sv_maxclients->integer ; i++) {
584 cl = &svs.clients[i];
585 if ( cl->state >= CS_CONNECTED ) {
586 ps = SV_GameClientNum( i );
587 Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n",
588 ps->persistant[PERS_SCORE], cl->ping, cl->name);
589 playerLength = strlen(player);
590 if (statusLength + playerLength >= sizeof(status) ) {
591 break; // can't hold any more
592 }
593 strcpy (status + statusLength, player);
594 statusLength += playerLength;
595 }
596 }
597
598 NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status );
599 }
600
601 /*
602 ================
603 SVC_Info
604
605 Responds with a short info message that should be enough to determine
606 if a user is interested in a server to do a full status
607 ================
608 */
SVC_Info(netadr_t from)609 void SVC_Info( netadr_t from ) {
610 int i, count, humans;
611 char *gamedir;
612 char infostring[MAX_INFO_STRING];
613
614 // ignore if we are in single player
615 if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) {
616 return;
617 }
618
619 /*
620 * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led
621 * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory.
622 */
623
624 // A maximum challenge length of 128 should be more than plenty.
625 if(strlen(Cmd_Argv(1)) > 128)
626 return;
627
628 // don't count privateclients
629 count = 0;
630 humans = 0;
631 for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) {
632 if ( svs.clients[i].state >= CS_CONNECTED ) {
633 count++;
634 if (svs.clients[i].netchan.remoteAddress.type != NA_BOT) {
635 humans++;
636 }
637 }
638 }
639
640 infostring[0] = 0;
641
642 // echo back the parameter to status. so servers can use it as a challenge
643 // to prevent timed spoofed reply packets that add ghost servers
644 Info_SetValueForKey( infostring, "challenge", Cmd_Argv(1) );
645
646 Info_SetValueForKey( infostring, "protocol", va("%i", com_protocol->integer) );
647 Info_SetValueForKey( infostring, "hostname", sv_hostname->string );
648 Info_SetValueForKey( infostring, "mapname", sv_mapname->string );
649 Info_SetValueForKey( infostring, "clients", va("%i", count) );
650 Info_SetValueForKey( infostring, "sv_maxclients",
651 va("%i", sv_maxclients->integer - sv_privateClients->integer ) );
652 Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) );
653 Info_SetValueForKey( infostring, "pure", va("%i", sv_pure->integer ) );
654 //Sago's things:
655 Info_SetValueForKey( infostring, "g_needpass", va("%i", (int)Cvar_VariableValue("g_needpass") ) );
656 Info_SetValueForKey( infostring, "g_humanplayers", va("%i", humans ) );
657 //Sago's end
658
659 #ifdef USE_VOIP
660 if (sv_voip->integer) {
661 Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) );
662 }
663 #endif
664
665 if( sv_minPing->integer ) {
666 Info_SetValueForKey( infostring, "minPing", va("%i", sv_minPing->integer) );
667 }
668 if( sv_maxPing->integer ) {
669 Info_SetValueForKey( infostring, "maxPing", va("%i", sv_maxPing->integer) );
670 }
671 gamedir = Cvar_VariableString( "fs_game" );
672 if( *gamedir ) {
673 Info_SetValueForKey( infostring, "game", gamedir );
674 }
675
676 NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring );
677 }
678
679 /*
680 ================
681 SVC_FlushRedirect
682
683 ================
684 */
SV_FlushRedirect(char * outputbuf)685 static void SV_FlushRedirect( char *outputbuf ) {
686 NET_OutOfBandPrint( NS_SERVER, svs.redirectAddress, "print\n%s", outputbuf );
687 }
688
689 /*
690 ===============
691 SVC_RemoteCommand
692
693 An rcon packet arrived from the network.
694 Shift down the remaining args
695 Redirect all printfs
696 ===============
697 */
SVC_RemoteCommand(netadr_t from,msg_t * msg)698 static void SVC_RemoteCommand( netadr_t from, msg_t *msg ) {
699 qboolean valid;
700 char remaining[1024];
701 // TTimo - scaled down to accumulate, but not overflow anything network wise, print wise etc.
702 // (OOB messages are the bottleneck here)
703 #define SV_OUTPUTBUF_LENGTH (1024 - 16)
704 char sv_outputbuf[SV_OUTPUTBUF_LENGTH];
705 char *cmd_aux;
706
707 // Prevent using rcon as an amplifier and make dictionary attacks impractical
708 if ( SVC_RateLimitAddress( from, 10, 1000 ) ) {
709 Com_DPrintf( "SVC_RemoteCommand: rate limit from %s exceeded, dropping request\n",
710 NET_AdrToString( from ) );
711 return;
712 }
713
714 if ( !strlen( sv_rconPassword->string ) ||
715 strcmp (Cmd_Argv(1), sv_rconPassword->string) ) {
716 static leakyBucket_t bucket;
717
718 // Make DoS via rcon impractical
719 if ( SVC_RateLimit( &bucket, 10, 1000 ) ) {
720 Com_DPrintf( "SVC_RemoteCommand: rate limit exceeded, dropping request\n" );
721 return;
722 }
723
724 valid = qfalse;
725 Com_Printf ("Bad rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
726 } else {
727 valid = qtrue;
728 Com_Printf ("Rcon from %s: %s\n", NET_AdrToString (from), Cmd_ArgsFrom(2) );
729 }
730
731 // start redirecting all print outputs to the packet
732 svs.redirectAddress = from;
733 Com_BeginRedirect (sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
734
735 if ( !strlen( sv_rconPassword->string ) ) {
736 Com_Printf ("No rconpassword set on the server.\n");
737 } else if ( !valid ) {
738 Com_Printf ("Bad rconpassword.\n");
739 } else {
740 remaining[0] = 0;
741
742 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543
743 // get the command directly, "rcon <pass> <command>" to avoid quoting issues
744 // extract the command by walking
745 // since the cmd formatting can fuckup (amount of spaces), using a dumb step by step parsing
746 cmd_aux = Cmd_Cmd();
747 cmd_aux+=4;
748 while(cmd_aux[0]==' ')
749 cmd_aux++;
750 while(cmd_aux[0] && cmd_aux[0]!=' ') // password
751 cmd_aux++;
752 while(cmd_aux[0]==' ')
753 cmd_aux++;
754
755 Q_strcat( remaining, sizeof(remaining), cmd_aux);
756
757 Cmd_ExecuteString (remaining);
758
759 }
760
761 Com_EndRedirect ();
762 }
763
764 /*
765 =================
766 SV_ConnectionlessPacket
767
768 A connectionless packet has four leading 0xff
769 characters to distinguish it from a game channel.
770 Clients that are in the game can still send
771 connectionless packets.
772 =================
773 */
SV_ConnectionlessPacket(netadr_t from,msg_t * msg)774 static void SV_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
775 char *s;
776 char *c;
777
778 MSG_BeginReadingOOB( msg );
779 MSG_ReadLong( msg ); // skip the -1 marker
780
781 if (!Q_strncmp("connect", (char *) &msg->data[4], 7)) {
782 Huff_Decompress(msg, 12);
783 }
784
785 s = MSG_ReadStringLine( msg );
786 Cmd_TokenizeString( s );
787
788 c = Cmd_Argv(0);
789 Com_DPrintf ("SV packet %s : %s\n", NET_AdrToString(from), c);
790
791 if (!Q_stricmp(c, "getstatus")) {
792 SVC_Status( from );
793 } else if (!Q_stricmp(c, "getinfo")) {
794 SVC_Info( from );
795 } else if (!Q_stricmp(c, "getchallenge")) {
796 SV_GetChallenge(from);
797 } else if (!Q_stricmp(c, "connect")) {
798 SV_DirectConnect( from );
799 #ifndef STANDALONE
800 } else if (!Q_stricmp(c, "ipAuthorize")) {
801 SV_AuthorizeIpPacket( from );
802 #endif
803 } else if (!Q_stricmp(c, "rcon")) {
804 SVC_RemoteCommand( from, msg );
805 } else if (!Q_stricmp(c, "disconnect")) {
806 // if a client starts up a local server, we may see some spurious
807 // server disconnect messages when their new server sees our final
808 // sequenced messages to the old client
809 } else {
810 Com_DPrintf ("bad connectionless packet from %s:\n%s\n",
811 NET_AdrToString (from), s);
812 }
813 }
814
815 //============================================================================
816
817 /*
818 =================
819 SV_PacketEvent
820 =================
821 */
SV_PacketEvent(netadr_t from,msg_t * msg)822 void SV_PacketEvent( netadr_t from, msg_t *msg ) {
823 int i;
824 client_t *cl;
825 int qport;
826
827 // check for connectionless packet (0xffffffff) first
828 if ( msg->cursize >= 4 && *(int *)msg->data == -1) {
829 SV_ConnectionlessPacket( from, msg );
830 return;
831 }
832
833 // read the qport out of the message so we can fix up
834 // stupid address translating routers
835 MSG_BeginReadingOOB( msg );
836 MSG_ReadLong( msg ); // sequence number
837 qport = MSG_ReadShort( msg ) & 0xffff;
838
839 // find which client the message is from
840 for (i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
841 if (cl->state == CS_FREE) {
842 continue;
843 }
844 if ( !NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) ) {
845 continue;
846 }
847 // it is possible to have multiple clients from a single IP
848 // address, so they are differentiated by the qport variable
849 if (cl->netchan.qport != qport) {
850 continue;
851 }
852
853 // the IP port can't be used to differentiate them, because
854 // some address translating routers periodically change UDP
855 // port assignments
856 if (cl->netchan.remoteAddress.port != from.port) {
857 Com_Printf( "SV_PacketEvent: fixing up a translated port\n" );
858 cl->netchan.remoteAddress.port = from.port;
859 }
860
861 // make sure it is a valid, in sequence packet
862 if (SV_Netchan_Process(cl, msg)) {
863 // zombie clients still need to do the Netchan_Process
864 // to make sure they don't need to retransmit the final
865 // reliable message, but they don't do any other processing
866 if (cl->state != CS_ZOMBIE) {
867 cl->lastPacketTime = svs.time; // don't timeout
868 SV_ExecuteClientMessage( cl, msg );
869 }
870 }
871 return;
872 }
873
874 // if we received a sequenced packet from an address we don't recognize,
875 // send an out of band disconnect packet to it
876 NET_OutOfBandPrint( NS_SERVER, from, "disconnect" );
877 }
878
879
880 /*
881 ===================
882 SV_CalcPings
883
884 Updates the cl->ping variables
885 ===================
886 */
SV_CalcPings(void)887 static void SV_CalcPings( void ) {
888 int i, j;
889 client_t *cl;
890 int total, count;
891 int delta;
892 playerState_t *ps;
893
894 for (i=0 ; i < sv_maxclients->integer ; i++) {
895 cl = &svs.clients[i];
896 if ( cl->state != CS_ACTIVE ) {
897 cl->ping = 999;
898 continue;
899 }
900 if ( !cl->gentity ) {
901 cl->ping = 999;
902 continue;
903 }
904 if ( cl->gentity->r.svFlags & SVF_BOT ) {
905 cl->ping = 0;
906 continue;
907 }
908
909 total = 0;
910 count = 0;
911 for ( j = 0 ; j < PACKET_BACKUP ; j++ ) {
912 if ( cl->frames[j].messageAcked <= 0 ) {
913 continue;
914 }
915 delta = cl->frames[j].messageAcked - cl->frames[j].messageSent;
916 count++;
917 total += delta;
918 }
919 if (!count) {
920 cl->ping = 999;
921 } else {
922 cl->ping = total/count;
923 if ( cl->ping > 999 ) {
924 cl->ping = 999;
925 }
926 }
927
928 // let the game dll know about the ping
929 ps = SV_GameClientNum( i );
930 ps->ping = cl->ping;
931 }
932 }
933
934 /*
935 ==================
936 SV_CheckTimeouts
937
938 If a packet has not been received from a client for timeout->integer
939 seconds, drop the conneciton. Server time is used instead of
940 realtime to avoid dropping the local client while debugging.
941
942 When a client is normally dropped, the client_t goes into a zombie state
943 for a few seconds to make sure any final reliable message gets resent
944 if necessary
945 ==================
946 */
SV_CheckTimeouts(void)947 static void SV_CheckTimeouts( void ) {
948 int i;
949 client_t *cl;
950 int droppoint;
951 int zombiepoint;
952
953 droppoint = svs.time - 1000 * sv_timeout->integer;
954 zombiepoint = svs.time - 1000 * sv_zombietime->integer;
955
956 for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
957 // message times may be wrong across a changelevel
958 if (cl->lastPacketTime > svs.time) {
959 cl->lastPacketTime = svs.time;
960 }
961
962 if (cl->state == CS_ZOMBIE
963 && cl->lastPacketTime < zombiepoint) {
964 // using the client id cause the cl->name is empty at this point
965 Com_DPrintf( "Going from CS_ZOMBIE to CS_FREE for client %d\n", i );
966 cl->state = CS_FREE; // can now be reused
967 continue;
968 }
969 if ( cl->state >= CS_CONNECTED && cl->lastPacketTime < droppoint) {
970 // wait several frames so a debugger session doesn't
971 // cause a timeout
972 if ( ++cl->timeoutCount > 5 ) {
973 SV_DropClient (cl, "timed out");
974 cl->state = CS_FREE; // don't bother with zombie state
975 }
976 } else {
977 cl->timeoutCount = 0;
978 }
979 }
980 }
981
982
983 /*
984 ==================
985 SV_CheckPaused
986 ==================
987 */
SV_CheckPaused(void)988 static qboolean SV_CheckPaused( void ) {
989 int count;
990 client_t *cl;
991 int i;
992
993 if ( !cl_paused->integer ) {
994 return qfalse;
995 }
996
997 // only pause if there is just a single client connected
998 count = 0;
999 for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) {
1000 if ( cl->state >= CS_CONNECTED && cl->netchan.remoteAddress.type != NA_BOT ) {
1001 count++;
1002 }
1003 }
1004
1005 if ( count > 1 ) {
1006 // don't pause
1007 if (sv_paused->integer)
1008 Cvar_Set("sv_paused", "0");
1009 return qfalse;
1010 }
1011
1012 if (!sv_paused->integer)
1013 Cvar_Set("sv_paused", "1");
1014 return qtrue;
1015 }
1016
1017 /*
1018 ==================
1019 SV_FrameMsec
1020 Return time in millseconds until processing of the next server frame.
1021 ==================
1022 */
SV_FrameMsec()1023 int SV_FrameMsec()
1024 {
1025 if(sv_fps)
1026 {
1027 int frameMsec;
1028
1029 frameMsec = 1000.0f / sv_fps->value;
1030
1031 if(frameMsec < sv.timeResidual)
1032 return 0;
1033 else
1034 return frameMsec - sv.timeResidual;
1035 }
1036 else
1037 return 1;
1038 }
1039
1040 /*
1041 ==================
1042 SV_Frame
1043
1044 Player movement occurs as a result of packet events, which
1045 happen before SV_Frame is called
1046 ==================
1047 */
SV_Frame(int msec)1048 void SV_Frame( int msec ) {
1049 int frameMsec;
1050 int startTime;
1051
1052 // the menu kills the server with this cvar
1053 if ( sv_killserver->integer ) {
1054 SV_Shutdown ("Server was killed");
1055 Cvar_Set( "sv_killserver", "0" );
1056 return;
1057 }
1058
1059 if (!com_sv_running->integer)
1060 {
1061 // Running as a server, but no map loaded
1062 #ifdef DEDICATED
1063 // Block until something interesting happens
1064 Sys_Sleep(-1);
1065 #endif
1066
1067 return;
1068 }
1069
1070 // allow pause if only the local client is connected
1071 if ( SV_CheckPaused() ) {
1072 return;
1073 }
1074
1075 // if it isn't time for the next frame, do nothing
1076 if ( sv_fps->integer < 1 ) {
1077 Cvar_Set( "sv_fps", "10" );
1078 }
1079
1080 frameMsec = 1000 / sv_fps->integer * com_timescale->value;
1081 // don't let it scale below 1ms
1082 if(frameMsec < 1)
1083 {
1084 Cvar_Set("timescale", va("%f", sv_fps->integer / 1000.0f));
1085 frameMsec = 1;
1086 }
1087
1088 sv.timeResidual += msec;
1089
1090 if (!com_dedicated->integer) SV_BotFrame (sv.time + sv.timeResidual);
1091
1092 // if time is about to hit the 32nd bit, kick all clients
1093 // and clear sv.time, rather
1094 // than checking for negative time wraparound everywhere.
1095 // 2giga-milliseconds = 23 days, so it won't be too often
1096 if ( svs.time > 0x70000000 ) {
1097 SV_Shutdown( "Restarting server due to time wrapping" );
1098 Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
1099 return;
1100 }
1101 // this can happen considerably earlier when lots of clients play and the map doesn't change
1102 if ( svs.nextSnapshotEntities >= 0x7FFFFFFE - svs.numSnapshotEntities ) {
1103 SV_Shutdown( "Restarting server due to numSnapshotEntities wrapping" );
1104 Cbuf_AddText( va( "map %s\n", Cvar_VariableString( "mapname" ) ) );
1105 return;
1106 }
1107
1108 if( sv.restartTime && sv.time >= sv.restartTime ) {
1109 sv.restartTime = 0;
1110 Cbuf_AddText( "map_restart 0\n" );
1111 return;
1112 }
1113
1114 // update infostrings if anything has been changed
1115 if ( cvar_modifiedFlags & CVAR_SERVERINFO ) {
1116 SV_SetConfigstring( CS_SERVERINFO, Cvar_InfoString( CVAR_SERVERINFO ) );
1117 cvar_modifiedFlags &= ~CVAR_SERVERINFO;
1118 }
1119 if ( cvar_modifiedFlags & CVAR_SYSTEMINFO ) {
1120 SV_SetConfigstring( CS_SYSTEMINFO, Cvar_InfoString_Big( CVAR_SYSTEMINFO ) );
1121 cvar_modifiedFlags &= ~CVAR_SYSTEMINFO;
1122 }
1123
1124 if ( com_speeds->integer ) {
1125 startTime = Sys_Milliseconds ();
1126 } else {
1127 startTime = 0; // quite a compiler warning
1128 }
1129
1130 // update ping based on the all received frames
1131 SV_CalcPings();
1132
1133 if (com_dedicated->integer) SV_BotFrame (sv.time);
1134
1135 // run the game simulation in chunks
1136 while ( sv.timeResidual >= frameMsec ) {
1137 sv.timeResidual -= frameMsec;
1138 svs.time += frameMsec;
1139 sv.time += frameMsec;
1140
1141 // let everything in the world think and move
1142 VM_Call (gvm, GAME_RUN_FRAME, sv.time);
1143 }
1144
1145 if ( com_speeds->integer ) {
1146 time_game = Sys_Milliseconds () - startTime;
1147 }
1148
1149 // check timeouts
1150 SV_CheckTimeouts();
1151
1152 // send messages back to the clients
1153 SV_SendClientMessages();
1154
1155 // send a heartbeat to the master if needed
1156 SV_MasterHeartbeat(sv_heartbeat->string);
1157 }
1158
1159 //============================================================================
1160
1161