From 73f3826ee6eb1c4e7300fa9e680f7affdbb8800c Mon Sep 17 00:00:00 2001
From: havoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Date: Thu, 16 Feb 2006 07:20:28 +0000
Subject: [PATCH] fixed bug that allowed accidental speed cheating with
 cl_movement 1 mode (move->time was being cleared by ApplyClientMove, so when
 ReadClientMove calculated how much to move since the last move, it always
 thought the last move was at time == 0, and then it clamped this delta to 0.1
 or less, which prevented it from being completely ridiculous, but still
 horrible) added kicking of speed cheaters (if they echo a timestamp that has
 not yet been issued by the server, they're clearly lying)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@5988 d7cf8633-e32d-0410-b094-e92efae38249
---
 sv_user.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/sv_user.c b/sv_user.c
index 6bdd8ba9..606d79aa 100644
--- a/sv_user.c
+++ b/sv_user.c
@@ -602,7 +602,7 @@ void SV_ClientThink(void)
 SV_ReadClientMove
 ===================
 */
-void SV_ReadClientMove (void)
+qboolean SV_ReadClientMove (void)
 {
 	int i;
 	double oldmovetime;
@@ -681,6 +681,17 @@ void SV_ReadClientMove (void)
 
 	if (!host_client->spawned)
 		memset(move, 0, sizeof(*move));
+	else if (move->time > sv.time + 0.01) // add a little fuzz factor due to float precision issues
+	{
+		Con_DPrintf("client move->time %f > sv.time %f, kicking\n", move->time, sv.time);
+		// if the client is lying about time, we have definitively detected a
+		// speed cheat attempt of the worst sort, and we can immediately kick
+		// the offending player off.
+		// this fixes the timestamp to prevent a speed cheat from working
+		move->time = sv.time;
+		// but we kick the player for good measure
+		return true;
+	}
 	else
 	{
 		// apply the latest accepted move to the entity fields
@@ -696,10 +707,12 @@ void SV_ReadClientMove (void)
 			prog->globals.server->frametime = oldframetime;
 		}
 	}
+	return false;
 }
 
 void SV_ApplyClientMove (void)
 {
+	double movetime;
 #ifdef NUM_PING_TIMES
 	int i;
 	float total;
@@ -750,7 +763,10 @@ void SV_ApplyClientMove (void)
 	if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_cursor_trace_ent))) val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM(move->cursor_entitynumber));
 	if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_ping))) val->_float = host_client->ping * 1000.0;
 
+	// don't clear move->time as it is used for applying cl_movement 1 moves
+	movetime = move->time;
 	memset(move, 0, sizeof(*move));
+	move->time = movetime;
 }
 
 void SV_FrameLost(int framenum)
@@ -854,7 +870,9 @@ void SV_ReadClientMessage(void)
 			return;
 
 		case clc_move:
-			SV_ReadClientMove ();
+			// if ReadClientMove returns true, the client tried to speed cheat
+			if (SV_ReadClientMove ())
+				SV_DropClient (false);
 			break;
 
 		case clc_ackframe:
-- 
2.39.5