Added cvars to configure (or disable) the server-side time cheat

protection.

sv_timekick: This cvar controls the number of times a player has to
be caught "cheating" before they get kicked. sv_timekick shows up in
serverinfo if changed from the default. If sv_timekick < 1, timecheat
detection is disabled. Default is 3.

sv_timekick_fuzz: This cvar affects how strict the protection is. The
higher the number, the more "fuzz" is applied, and the less strict the
detection code is. Raise this if your players are being kicked for packet
loss and lag. Default is 10, giving a fuzz factor of about 1 percent.

sv_timekick_interval: This cvar controls how often, in seconds, the time
tally is counted. Lowering this value increases the chance of false
positives, but helps to minimize the amount of damage a timecheating
player can cause. Default is 30 seconds.
This commit is contained in:
Jeff Teunissen 2000-04-06 14:52:56 +00:00
parent 217e8c9a5c
commit 5fe2d742d5
2 changed files with 52 additions and 56 deletions

View file

@ -78,6 +78,10 @@ cvar_t *pausable;
cvar_t *sv_fraglogdir;
cvar_t *sv_timekick; // Time cheat protection
cvar_t *sv_timekick_fuzz; // Timecheat sensitivity
cvar_t *sv_timekick_interval; // Timecheat check interval
//
// game rules mirrored in svs.info
//
@ -1415,6 +1419,10 @@ void SV_InitLocal (void)
pausable = Cvar_Get ("pausable","1",0,"None");
sv_timekick = Cvar_Get( "sv_timekick", "3", CVAR_SERVERINFO, "Time cheat protection");
sv_timekick_fuzz = Cvar_Get( "sv_timekick_fuzz", "10", CVAR_NONE, "Time cheat \"fuzz factor\"");
sv_timekick_interval = Cvar_Get( "sv_timekick_interval", "30", CVAR_NONE, "Time cheat check interval");
sv_fraglogdir = Cvar_Get ("fraglogdir","",0,"Where to store fraglog files");
Cmd_AddCommand ("addip", SV_AddIP_f);
@ -1447,20 +1455,20 @@ void SV_InitLocal (void)
// Lots of nifty checks done in here.. Lives by the heartbeat
void HeartBeat_Check( void) {
void
HeartBeat_Check( void )
{
int i;
client_t *cl;
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
{
for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++) {
if (cl->state == cs_connected || cl->state == cs_spawned) {
// Put stuff in here that you want done to every client
// Slades maxrate function
if((1/cl->netchan.rate) > sv_maxrate->value && sv_maxrate->value) {
SV_BroadcastPrintf (PRINT_HIGH, "%s was kicked for having his rate to high\n", cl->name);
SV_ClientPrintf (cl, PRINT_HIGH, "You were kicked from the game for having a rate higher then %5.0f\n", sv_maxrate->value);
SV_BroadcastPrintf (PRINT_HIGH, "%s has been kicked for having too high a rate.\n", cl->name);
SV_ClientPrintf (cl, PRINT_HIGH, "You have been kicked for having a rate higher than %5.0f.\n", sv_maxrate->value);
SV_DropClient(cl);
}

View file

@ -44,12 +44,16 @@ cvar_t *cl_rollangle;
cvar_t *sv_spectalk;
cvar_t *sv_mapcheck;
extern cvar_t *sv_timekick;
extern cvar_t *sv_timekick_fuzz;
extern cvar_t *sv_timekick_interval;
extern vec3_t player_mins;
extern int fp_messages, fp_persecond, fp_secondsdead;
extern char fp_msg[];
extern cvar_t *pausable;
static int loss;
extern int fp_messages, fp_persecond, fp_secondsdead;
extern char fp_msg[];
extern cvar_t *pausable;
static int loss;
/*
============================================================
@ -1372,18 +1376,11 @@ void SV_PreRunCmd(void)
memset(playertouch, 0, sizeof(playertouch));
}
// Over how long do we make the checks?
#define CHECK_TIME 30
// How many failed checks before we boot the guy?
#define CHECK_LIMIT 3
/*
===========
SV_RunCmd
===========
SV_RunCmd
*/
void SV_RunCmd (usercmd_t *ucmd, qboolean inside)
void
SV_RunCmd (usercmd_t *ucmd, qboolean inside)
{
edict_t *ent;
int i, n, oldmsec;
@ -1393,20 +1390,20 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean inside)
if (!inside) {
host_client->msecs += ucmd->msec;
if ((tmp_time = realtime - host_client->last_check) >= CHECK_TIME) {
tmp_time *= 1010;
if (host_client->msecs > (int) (tmp_time + 0.5)) {
if ((sv_timekick->value >= 1) &&
(tmp_time = realtime - host_client->last_check) >= sv_timekick_interval->value) {
tmp_time *= (1000 + sv_timekick_fuzz->value);
if (host_client->msecs > (int) tmp_time) {
host_client->msec_cheating++;
SV_BroadcastPrintf(PRINT_HIGH,
va("%s thinks %d msecs pass in %f msecs. (Strike %d/%d)\n",
SV_BroadcastPrintf( PRINT_HIGH,
va("%s thinks %d msecs pass in %f msecs. (Strike %d/%d)\n",
host_client->name, host_client->msecs, tmp_time,
host_client->msec_cheating, CHECK_LIMIT));
host_client->msec_cheating, (int)sv_timekick->value));
if (host_client->msec_cheating >= CHECK_LIMIT) {
SV_BroadcastPrintf(PRINT_HIGH,
va("Strike %d for %s!!\n",
host_client->msec_cheating, host_client->name));
SV_BroadcastPrintf(PRINT_HIGH, "Please see http://www.quakeforge.net/speed_cheat.html for infomation on the cheat detection, and to explain how some may be cheating without knowing it.\n");
if (host_client->msec_cheating >= sv_timekick->value) {
SV_BroadcastPrintf(PRINT_HIGH, va("Strike %d for %s!!\n",
host_client->msec_cheating, host_client->name));
SV_BroadcastPrintf(PRINT_HIGH, "Please see http://www.quakeforge.net/speed_cheat.php for infomation on QuakeForge's timecheat protection, and to explain how some may be cheating without knowing it.\n");
SV_DropClient(host_client);
}
}
@ -1440,10 +1437,8 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean inside)
//
// angles
// show 1/3 the pitch angle and all the roll angle
if (sv_player->v.health > 0)
{
if (!sv_player->v.fixangle)
{
if (sv_player->v.health > 0) {
if (!sv_player->v.fixangle) {
sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
}
@ -1451,12 +1446,9 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean inside)
V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
}
host_frametime = ucmd->msec * 0.001;
if (host_frametime > 0.1)
host_frametime = 0.1;
host_frametime = max(0.1, ucmd->msec * 0.001);
if (!host_client->spectator)
{
if (!host_client->spectator) {
pr_global_struct->frametime = host_frametime;
pr_global_struct->time = sv.time;
@ -1483,8 +1475,7 @@ void SV_RunCmd (usercmd_t *ucmd, qboolean inside)
movevars.entgravity = host_client->entgravity;
movevars.maxspeed = host_client->maxspeed;
for (i=0 ; i<3 ; i++)
{
for (i=0 ; i<3 ; i++) {
pmove_mins[i] = pmove.origin[i] - 256;
pmove_maxs[i] = pmove.origin[i] + 256;
}
@ -1513,13 +1504,12 @@ if (sv_player->v.health > 0 && before && !after )
sv_player->v.teleport_time = pmove.waterjumptime;
sv_player->v.waterlevel = waterlevel;
sv_player->v.watertype = watertype;
if (onground != -1)
{
if (onground != -1) {
sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
}
else
} else {
sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;
}
for (i=0 ; i<3 ; i++)
sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);
@ -1533,14 +1523,12 @@ if (sv_player->v.health > 0 && before && !after )
VectorCopy (pmove.angles, sv_player->v.v_angle);
if (!host_client->spectator)
{
if (!host_client->spectator) {
// link into place and touch triggers
SV_LinkEdict (sv_player, true);
// touch other objects
for (i=0 ; i<pmove.numtouch ; i++)
{
for (i=0 ; i<pmove.numtouch ; i++) {
n = pmove.physents[pmove.touchindex[i]].info;
ent = EDICT_NUM(n);
if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
@ -1554,12 +1542,12 @@ if (sv_player->v.health > 0 && before && !after )
}
/*
===========
SV_PostRunCmd
===========
Done after running a player command.
SV_PostRunCmd
Done after running a player command.
*/
void SV_PostRunCmd(void)
void
SV_PostRunCmd(void)
{
// run post-think