mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Refactor challenge creation, no more duplicated memory shenanigans
This commit is contained in:
parent
f0e6e5c962
commit
5a52199dc8
4 changed files with 140 additions and 144 deletions
244
src/d_clisrv.c
244
src/d_clisrv.c
|
|
@ -183,9 +183,8 @@ consvar_t cv_allowguests = CVAR_INIT ("allowguests", "On", CV_SAVE, CV_OnOff, NU
|
|||
consvar_t cv_nochallenge = CVAR_INIT ("nochallenge", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badresults = CVAR_INIT ("badresults", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_noresults = CVAR_INIT ("noresults", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badjointime = CVAR_INIT ("badjointime", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badtime = CVAR_INIT ("badtime", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badip = CVAR_INIT ("badip", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badchallengetime = CVAR_INIT ("badchallengetime", "0", 0, CV_Unsigned, NULL);
|
||||
#endif
|
||||
|
||||
// engine
|
||||
|
|
@ -220,6 +219,74 @@ consvar_t cv_httpsource = CVAR_INIT ("http_source", "", CV_SAVE, NULL, NULL);
|
|||
|
||||
consvar_t cv_kicktime = CVAR_INIT ("kicktime", "10", CV_SAVE, CV_Unsigned, NULL);
|
||||
|
||||
// https://github.com/jameds/holepunch/blob/master/holepunch.c#L75
|
||||
static int IsExternalAddress (const void *p)
|
||||
{
|
||||
const int a = ((const unsigned char*)p)[0];
|
||||
const int b = ((const unsigned char*)p)[1];
|
||||
|
||||
if (*(const int*)p == ~0)/* 255.255.255.255 */
|
||||
return 0;
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0:
|
||||
case 10:
|
||||
case 127:
|
||||
return 0;
|
||||
case 172:
|
||||
return (b & ~15) != 16;/* 16 - 31 */
|
||||
case 192:
|
||||
return b != 168;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GenerateChallenge(uint8_t *buf)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
csprng(buf, sizeof(&buf)); // Random noise so the client can't guess...
|
||||
memcpy(buf, &now, sizeof(now)); // ...timestamp so we can't reuse it...
|
||||
memcpy(buf + sizeof(now), &ourIP, sizeof(ourIP)); // ...and server IP so others can't reuse it.
|
||||
|
||||
#ifdef DEVELOP
|
||||
if (cv_badtime.value)
|
||||
{
|
||||
CV_AddValue(&cv_badtime, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badtime enabled, trashing time in auth message\n");
|
||||
memset(buf, 0, sizeof(now));
|
||||
}
|
||||
|
||||
if (cv_badip.value)
|
||||
{
|
||||
CV_AddValue(&cv_badip, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badip enabled, trashing IP in auth message\n");
|
||||
memset(buf + sizeof(now), 0, sizeof(ourIP));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
shouldsign_t ShouldSignChallenge(uint8_t *message)
|
||||
{
|
||||
time_t then, now;
|
||||
UINT32 claimedIP, realIP;
|
||||
|
||||
now = time(NULL);
|
||||
memcpy(&then, message, sizeof(then));
|
||||
memcpy(&claimedIP, message + sizeof(then), sizeof(claimedIP));
|
||||
realIP = *I_GetNodeAddressInt(servernode);
|
||||
|
||||
if (abs(now - then) > 60*5)
|
||||
return SIGN_BADTIME;
|
||||
|
||||
if (realIP != claimedIP && IsExternalAddress(&realIP))
|
||||
return SIGN_BADIP;
|
||||
|
||||
return SIGN_OK;
|
||||
}
|
||||
|
||||
static inline void *G_DcpyTiccmd(void* dest, const ticcmd_t* src, const size_t n)
|
||||
{
|
||||
const size_t d = n / sizeof(ticcmd_t);
|
||||
|
|
@ -815,31 +882,6 @@ static boolean CL_AskFileList(INT32 firstfile)
|
|||
return HSendPacket(servernode, false, 0, sizeof (INT32));
|
||||
}
|
||||
|
||||
// https://github.com/jameds/holepunch/blob/master/holepunch.c#L75
|
||||
static int IsExternalAddress (const void *p)
|
||||
{
|
||||
const int a = ((const unsigned char*)p)[0];
|
||||
const int b = ((const unsigned char*)p)[1];
|
||||
|
||||
if (*(const int*)p == ~0)/* 255.255.255.255 */
|
||||
return 0;
|
||||
|
||||
switch (a)
|
||||
{
|
||||
case 0:
|
||||
case 10:
|
||||
case 127:
|
||||
return 0;
|
||||
case 172:
|
||||
return (b & ~15) != 16;/* 16 - 31 */
|
||||
case 192:
|
||||
return b != 168;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Sends a special packet to declare how many players in local
|
||||
* Used only in arbitratrenetstart()
|
||||
* Sends a PT_CLIENTJOIN packet to the server
|
||||
|
|
@ -887,22 +929,23 @@ static boolean CL_SendJoin(void)
|
|||
|
||||
if (client && netgame)
|
||||
{
|
||||
UINT32 claimedIP;
|
||||
UINT32 realIP = *I_GetNodeAddressInt(servernode);
|
||||
time_t receivedTime;
|
||||
time_t now = time(NULL);
|
||||
shouldsign_t safe = ShouldSignChallenge(awaitingChallenge);
|
||||
|
||||
memcpy(&claimedIP, awaitingChallenge, sizeof(claimedIP));
|
||||
memcpy(&receivedTime, awaitingChallenge + sizeof(claimedIP), sizeof(receivedTime));
|
||||
|
||||
if (realIP != claimedIP && IsExternalAddress(&realIP))
|
||||
if (safe != SIGN_OK)
|
||||
{
|
||||
I_Error("External server IP didn't match the message it sent.\nSomething is very wrong here.");
|
||||
}
|
||||
|
||||
if (abs(now - receivedTime) > 60*5)
|
||||
{
|
||||
I_Error("External server sent a message with an unusual timestamp.\nReceived: %ld\nNow: %ld\nCheck your clocks!", receivedTime, now);
|
||||
if (safe == SIGN_BADIP)
|
||||
{
|
||||
I_Error("External server IP didn't match the message it sent.");
|
||||
}
|
||||
else if (safe == SIGN_BADTIME)
|
||||
{
|
||||
I_Error("External server sent a message with an unusual timestamp.\nCheck your clocks!");
|
||||
}
|
||||
else
|
||||
{
|
||||
I_Error("External server asked for a signature on something strange.\nPlease notify a developer if you've seen this more than once.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4342,6 +4385,7 @@ static void HandleConnect(SINT8 node)
|
|||
else
|
||||
{
|
||||
CONS_Printf("Adding remote. Doing sigcheck for node %d, ID %s\n", node, GetPrettyRRID(lastReceivedKey[node][i], true));
|
||||
|
||||
if (IsSplitPlayerOnNodeGuest(node, i)) // We're a GUEST and the server throws out our keys anyway.
|
||||
{
|
||||
sigcheck = 0; // Always succeeds. Yes, this is a success response. C R Y P T O
|
||||
|
|
@ -4356,7 +4400,6 @@ static void HandleConnect(SINT8 node)
|
|||
sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse[i], lastReceivedKey[node][i], lastSentChallenge[node], 32);
|
||||
}
|
||||
|
||||
|
||||
if (netgame && sigcheck != 0)
|
||||
{
|
||||
SV_SendRefuse(node, M_GetText("Signature verification failed."));
|
||||
|
|
@ -5320,37 +5363,29 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
CL_PrepareDownloadLuaFile();
|
||||
break;
|
||||
case PT_CHALLENGEALL: ; // -Wpedantic
|
||||
if (demo.playback)
|
||||
if (demo.playback || node != servernode) // SERVER should still respond to this to prove its own identity, just not from clients.
|
||||
break;
|
||||
|
||||
if (node != servernode)
|
||||
break;
|
||||
|
||||
int challengeplayers;
|
||||
time_t now, then;
|
||||
UINT32 claimedIP;
|
||||
|
||||
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
|
||||
|
||||
now = time(NULL);
|
||||
memcpy(&then, lastChallengeAll, sizeof(then));
|
||||
shouldsign_t safe = ShouldSignChallenge(lastChallengeAll);
|
||||
|
||||
CONS_Printf("Time offset: %d\n", abs(now - then));
|
||||
|
||||
if (abs(now - then) > 300)
|
||||
if (safe != SIGN_OK)
|
||||
{
|
||||
HandleSigfail("Bad challenge - time difference, check clocks");
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(&claimedIP, lastChallengeAll + sizeof(then), sizeof(claimedIP));
|
||||
UINT32 realIP = *I_GetNodeAddressInt(servernode);
|
||||
|
||||
CONS_Printf("Got IP %u, known IP %u\n", claimedIP, gamemap);
|
||||
|
||||
if (realIP != claimedIP && IsExternalAddress(&realIP))
|
||||
{
|
||||
HandleSigfail("Bad challenge - server claimed wrong IP");
|
||||
if (safe == SIGN_BADIP)
|
||||
{
|
||||
HandleSigfail("External server sent the wrong IP");
|
||||
}
|
||||
else if (safe == SIGN_BADTIME)
|
||||
{
|
||||
HandleSigfail("Bad timestamp - check your clocks");
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleSigfail("Unknown auth error - contact a developer");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -5398,41 +5433,38 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
HSendPacket(servernode, true, 0, sizeof(netbuffer->u.responseall));
|
||||
break;
|
||||
case PT_RESPONSEALL:
|
||||
if (demo.playback)
|
||||
if (demo.playback || client)
|
||||
break;
|
||||
|
||||
if (server)
|
||||
int responseplayer;
|
||||
//CONS_Printf("Got PT_RESPONSEALL from node %d, player %d\n", node, nodetoplayer[node]);
|
||||
for (responseplayer = 0; responseplayer < MAXSPLITSCREENPLAYERS; responseplayer++)
|
||||
{
|
||||
int responseplayer;
|
||||
//CONS_Printf("Got PT_RESPONSEALL from node %d, player %d\n", node, nodetoplayer[node]);
|
||||
for (responseplayer = 0; responseplayer < MAXSPLITSCREENPLAYERS; responseplayer++)
|
||||
{
|
||||
int targetplayer = NodeToSplitPlayer(node, responseplayer);
|
||||
if (targetplayer == -1)
|
||||
continue;
|
||||
int targetplayer = NodeToSplitPlayer(node, responseplayer);
|
||||
if (targetplayer == -1)
|
||||
continue;
|
||||
|
||||
if (IsSplitPlayerOnNodeGuest(node, responseplayer))
|
||||
if (IsSplitPlayerOnNodeGuest(node, responseplayer))
|
||||
{
|
||||
CONS_Printf("GUEST on node %d player %d split %d, leaving blank\n", node, targetplayer, responseplayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf("receiving %s pk %s\n", GetPrettyRRID(lastChallengeAll, true), GetPrettyRRID(players[targetplayer].public_key, true));
|
||||
if (crypto_eddsa_check(netbuffer->u.responseall.signature[responseplayer],
|
||||
players[targetplayer].public_key, lastChallengeAll, sizeof(lastChallengeAll)))
|
||||
{
|
||||
CONS_Printf("GUEST on node %d player %d split %d, leaving blank\n", node, targetplayer, responseplayer);
|
||||
CONS_Alert(CONS_WARNING, "Invalid PT_RESPONSEALL from node %d player %d split %d\n", node, targetplayer, responseplayer);
|
||||
if (playernode[targetplayer] != 0) // NO IDEA.
|
||||
{
|
||||
SendKick(targetplayer, KICK_MSG_SIGFAIL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
CONS_Printf("receiving %s pk %s\n", GetPrettyRRID(lastChallengeAll, true), GetPrettyRRID(players[targetplayer].public_key, true));
|
||||
if (crypto_eddsa_check(netbuffer->u.responseall.signature[responseplayer],
|
||||
players[targetplayer].public_key, lastChallengeAll, sizeof(lastChallengeAll)))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Invalid PT_RESPONSEALL from node %d player %d split %d\n", node, targetplayer, responseplayer);
|
||||
if (playernode[targetplayer] != 0) // NO IDEA.
|
||||
{
|
||||
SendKick(targetplayer, KICK_MSG_SIGFAIL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(lastReceivedSignature[targetplayer], netbuffer->u.responseall.signature[responseplayer], sizeof(lastReceivedSignature[targetplayer]));
|
||||
CONS_Printf("Writing signature %s for node %d player %d split %d\n", GetPrettyRRID(lastReceivedSignature[targetplayer], true), node, targetplayer, responseplayer);
|
||||
}
|
||||
memcpy(lastReceivedSignature[targetplayer], netbuffer->u.responseall.signature[responseplayer], sizeof(lastReceivedSignature[targetplayer]));
|
||||
CONS_Printf("Writing signature %s for node %d player %d split %d\n", GetPrettyRRID(lastReceivedSignature[targetplayer], true), node, targetplayer, responseplayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5444,16 +5476,7 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
|
||||
CONS_Printf("Got PT_RESULTSALL\n");
|
||||
|
||||
if (demo.playback)
|
||||
break;
|
||||
|
||||
if (server)
|
||||
break;
|
||||
|
||||
if (node != servernode)
|
||||
break;
|
||||
|
||||
if (!expectChallenge)
|
||||
if (demo.playback || server || node != servernode || !expectChallenge)
|
||||
break;
|
||||
|
||||
CONS_Printf("Checking PT_RESULTSALL\n");
|
||||
|
|
@ -6335,20 +6358,7 @@ static void UpdateChallenges(void)
|
|||
|
||||
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
|
||||
|
||||
time_t now = time(NULL);
|
||||
#ifdef DEVELOP
|
||||
if (cv_badchallengetime.value)
|
||||
{
|
||||
CV_AddValue(&cv_badchallengetime, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badchallengetime enabled, scrubbing time from PT_CHALLENGEALL\n");
|
||||
now = 0;
|
||||
}
|
||||
#endif
|
||||
CONS_Printf("now: %ld, ip: %u\n", now, ourIP);
|
||||
csprng(netbuffer->u.challengeall.secret, sizeof(netbuffer->u.challengeall.secret)); // Random noise so the client can't guess...
|
||||
memcpy(netbuffer->u.challengeall.secret, &now, sizeof(now)); // ...timestamp...
|
||||
memcpy(netbuffer->u.challengeall.secret + sizeof(now), &ourIP, sizeof(ourIP)); // ...and server IP so the server can't reuse it.
|
||||
|
||||
GenerateChallenge(netbuffer->u.challengeall.secret);
|
||||
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
|
||||
|
||||
memset(lastReceivedSignature, 0, sizeof(lastReceivedSignature));
|
||||
|
|
|
|||
|
|
@ -130,6 +130,13 @@ typedef enum
|
|||
NUMPACKETTYPE
|
||||
} packettype_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SIGN_OK,
|
||||
SIGN_BADTIME,
|
||||
SIGN_BADIP
|
||||
} shouldsign_t;
|
||||
|
||||
#ifdef PACKETDROP
|
||||
void Command_Drop(void);
|
||||
void Command_Droprate(void);
|
||||
|
|
@ -530,15 +537,17 @@ extern consvar_t cv_allowguests;
|
|||
extern consvar_t cv_nochallenge;
|
||||
extern consvar_t cv_badresults;
|
||||
extern consvar_t cv_noresults;
|
||||
extern consvar_t cv_badjointime;
|
||||
extern consvar_t cv_badtime;
|
||||
extern consvar_t cv_badip;
|
||||
extern consvar_t cv_badchallengetime;
|
||||
#endif
|
||||
|
||||
// Used in d_net, the only dependence
|
||||
tic_t ExpandTics(INT32 low, tic_t basetic);
|
||||
void D_ClientServerInit(void);
|
||||
|
||||
void GenerateChallenge(uint8_t *buf);
|
||||
shouldsign_t ShouldSignChallenge(uint8_t *message);
|
||||
|
||||
// Initialise the other field
|
||||
void RegisterNetXCmd(netxcmd_t id, void (*cmd_f)(UINT8 **p, INT32 playernum));
|
||||
void SendNetXCmdForPlayer(UINT8 playerid, netxcmd_t id, const void *param, size_t nparam);
|
||||
|
|
|
|||
|
|
@ -956,9 +956,8 @@ void D_RegisterClientCommands(void)
|
|||
CV_RegisterVar(&cv_nochallenge);
|
||||
CV_RegisterVar(&cv_badresults);
|
||||
CV_RegisterVar(&cv_noresults);
|
||||
CV_RegisterVar(&cv_badjointime);
|
||||
CV_RegisterVar(&cv_badtime);
|
||||
CV_RegisterVar(&cv_badip);
|
||||
CV_RegisterVar(&cv_badchallengetime);
|
||||
#endif
|
||||
|
||||
// HUD
|
||||
|
|
|
|||
|
|
@ -1323,30 +1323,8 @@ void PT_ClientKey(INT32 node)
|
|||
CONS_Printf("Got keys from node %d, %s / %s / %s / %s\n", node, GetPrettyRRID(lastReceivedKey[node][0], true), GetPrettyRRID(lastReceivedKey[node][1], true), GetPrettyRRID(lastReceivedKey[node][2], true), GetPrettyRRID(lastReceivedKey[node][3], true));
|
||||
|
||||
netbuffer->packettype = PT_SERVERCHALLENGE;
|
||||
time_t now = time(NULL);
|
||||
|
||||
#ifdef DEVELOP
|
||||
if (cv_badjointime.value)
|
||||
{
|
||||
CV_AddValue(&cv_badjointime, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badjointime enabled, scrubbing time from PT_SERVERCHALLENGE\n");
|
||||
now = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Include our IP and current time in the message to be signed, to guard against signature reuse.
|
||||
csprng(lastSentChallenge[node], sizeof(serverchallenge_pak));
|
||||
memcpy(lastSentChallenge[node], &ourIP, sizeof(ourIP));
|
||||
memcpy(lastSentChallenge[node] + sizeof(ourIP), &now, sizeof(time_t));
|
||||
|
||||
#ifdef DEVELOP
|
||||
if (cv_badip.value)
|
||||
{
|
||||
CV_AddValue(&cv_badip, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badip enabled, scrubbing IP from PT_SERVERCHALLENGE\n");
|
||||
memset(lastSentChallenge[node], 0, sizeof(ourIP));
|
||||
}
|
||||
#endif
|
||||
GenerateChallenge(lastSentChallenge[node]);
|
||||
|
||||
memcpy(&netbuffer->u.serverchallenge, lastSentChallenge[node], sizeof(serverchallenge_pak));
|
||||
HSendPacket(node, false, 0, sizeof (serverchallenge_pak));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue