Cleanup and comments

This commit is contained in:
AJ Martinez 2023-03-23 23:05:22 -07:00 committed by James R
parent 5a52199dc8
commit ecc2c65742
4 changed files with 203 additions and 188 deletions

View file

@ -167,7 +167,7 @@ uint8_t lastReceivedSignature[MAXPLAYERS][64]; // Everyone's response to lastCha
uint8_t knownWhenChallenged[MAXPLAYERS][32]; // Everyone a client saw at the moment a challenge should be initiated uint8_t knownWhenChallenged[MAXPLAYERS][32]; // Everyone a client saw at the moment a challenge should be initiated
boolean expectChallenge = false; // Were we in-game before a client-to-client challenge should have been sent? boolean expectChallenge = false; // Were we in-game before a client-to-client challenge should have been sent?
uint8_t priorGamestateKeySave[MAXPLAYERS][32]; // Make a note of keys before consuming a new gamestate, and if the server tries to send us a gamestate where keys differ, assume shenanigans uint8_t priorKeys[MAXPLAYERS][32]; // Make a note of keys before consuming a new gamestate, and if the server tries to send us a gamestate where keys differ, assume shenanigans
boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not boolean serverisfull = false; //lets us be aware if the server was full after we check files, but before downloading, so we can ask if the user still wants to download or not
tic_t firstconnectattempttime = 0; tic_t firstconnectattempttime = 0;
@ -244,12 +244,13 @@ static int IsExternalAddress (const void *p)
} }
// Generate a message for an authenticating client to sign, with some guarantees about who we are.
void GenerateChallenge(uint8_t *buf) void GenerateChallenge(uint8_t *buf)
{ {
time_t now = time(NULL); time_t now = time(NULL);
csprng(buf, sizeof(&buf)); // Random noise so the client can't guess... csprng(buf, sizeof(&buf)); // Random noise as a baseline, but...
memcpy(buf, &now, sizeof(now)); // ...timestamp so we can't reuse it... memcpy(buf, &now, sizeof(now)); // Timestamp limits the reuse window.
memcpy(buf + sizeof(now), &ourIP, sizeof(ourIP)); // ...and server IP so others can't reuse it. memcpy(buf + sizeof(now), &ourIP, sizeof(ourIP)); // IP prevents captured signatures from being used elsewhere.
#ifdef DEVELOP #ifdef DEVELOP
if (cv_badtime.value) if (cv_badtime.value)
@ -268,6 +269,8 @@ void GenerateChallenge(uint8_t *buf)
#endif #endif
} }
// Modified servers can throw softballs or reuse challenges.
// Don't sign anything that wasn't generated just for us!
shouldsign_t ShouldSignChallenge(uint8_t *message) shouldsign_t ShouldSignChallenge(uint8_t *message)
{ {
time_t then, now; time_t then, now;
@ -945,7 +948,7 @@ static boolean CL_SendJoin(void)
{ {
I_Error("External server asked for a signature on something strange.\nPlease notify a developer if you've seen this more than once."); I_Error("External server asked for a signature on something strange.\nPlease notify a developer if you've seen this more than once.");
} }
return; return false;
} }
} }
@ -1486,7 +1489,7 @@ static void CL_LoadReceivedSavegame(boolean reloading)
int i; int i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (memcmp(priorGamestateKeySave[i], players[i].public_key, sizeof(priorGamestateKeySave[i])) != 0) if (memcmp(priorKeys[i], players[i].public_key, sizeof(priorKeys[i])) != 0)
{ {
HandleSigfail("Gamestate reload contained new keys"); HandleSigfail("Gamestate reload contained new keys");
break; break;
@ -4378,22 +4381,23 @@ static void HandleConnect(SINT8 node)
return; return;
} }
if (node == 0) if (node == 0) // Hey, that's us. We're always allowed to do what we want.
{ {
memcpy(lastReceivedKey[node][i], PR_GetLocalPlayerProfile(i)->public_key, sizeof(lastReceivedKey[node][i])); memcpy(lastReceivedKey[node][i], PR_GetLocalPlayerProfile(i)->public_key, sizeof(lastReceivedKey[node][i]));
} }
else else // Remote player, gotta check their signature.
{ {
CONS_Printf("Adding remote. Doing sigcheck for node %d, ID %s\n", node, GetPrettyRRID(lastReceivedKey[node][i], true)); 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. 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
if (!cv_allowguests.value) if (!cv_allowguests.value)
{ {
SV_SendRefuse(node, M_GetText("The server doesn't allow GUESTs.\nCreate a profile to join!")); SV_SendRefuse(node, M_GetText("The server doesn't allow GUESTs.\nCreate a profile to join!"));
return; return;
} }
sigcheck = 0; // Always succeeds. Yes, this is a success response. C R Y P T O
} }
else else
{ {
@ -4488,6 +4492,12 @@ static void HandleTimeout(SINT8 node)
// Called when a signature check fails and we suspect the server is playing games. // Called when a signature check fails and we suspect the server is playing games.
void HandleSigfail(const char *string) void HandleSigfail(const char *string)
{ {
if (server) // This situation is basically guaranteed to be nonsense.
{
CONS_Alert(CONS_ERROR, "Auth error! %s\n", string);
return; // Keep the game running, you're probably testing.
}
LUA_HookBool(false, HOOK(GameQuit)); LUA_HookBool(false, HOOK(GameQuit));
D_QuitNetGame(); D_QuitNetGame();
CL_Reset(); CL_Reset();
@ -4528,10 +4538,12 @@ static void PT_WillResendGamestate(void)
if (server || cl_redownloadinggamestate) if (server || cl_redownloadinggamestate)
return; return;
// Don't let the server pull a fast one with everyone's identity!
// Save the public keys we see, so if the server tries to swap one, we'll know.
int i; int i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
memcpy(priorGamestateKeySave[i], players[i].public_key, sizeof(priorGamestateKeySave[i])); memcpy(priorKeys[i], players[i].public_key, sizeof(priorKeys[i]));
} }
// Send back a PT_CANRECEIVEGAMESTATE packet to the server // Send back a PT_CANRECEIVEGAMESTATE packet to the server
@ -4807,6 +4819,8 @@ static void HandlePacketFromAwayNode(SINT8 node)
{ {
PT_ClientKey(node); PT_ClientKey(node);
// Client's not in the server yet, but we still need to lock up the node.
// Otherwise, someone else could request a challenge on the same node and trash it.
nodeneedsauth[node] = true; nodeneedsauth[node] = true;
freezetimeout[node] = I_GetTime() + jointimeout; freezetimeout[node] = I_GetTime() + jointimeout;
@ -5371,27 +5385,20 @@ static void HandlePacketFromPlayer(SINT8 node)
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll)); memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
shouldsign_t safe = ShouldSignChallenge(lastChallengeAll); shouldsign_t safe = ShouldSignChallenge(lastChallengeAll);
if (safe != SIGN_OK) if (safe != SIGN_OK)
{ {
if (safe == SIGN_BADIP) if (safe == SIGN_BADIP)
{
HandleSigfail("External server sent the wrong IP"); HandleSigfail("External server sent the wrong IP");
}
else if (safe == SIGN_BADTIME) else if (safe == SIGN_BADTIME)
{
HandleSigfail("Bad timestamp - check your clocks"); HandleSigfail("Bad timestamp - check your clocks");
}
else else
{
HandleSigfail("Unknown auth error - contact a developer"); HandleSigfail("Unknown auth error - contact a developer");
}
break; break;
} }
netbuffer->packettype = PT_RESPONSEALL; netbuffer->packettype = PT_RESPONSEALL;
#ifdef DEVELOP #ifdef DEVELOP
if (cv_noresponse.value) if (cv_noresponse.value)
{ {
CV_AddValue(&cv_noresponse, -1); CV_AddValue(&cv_noresponse, -1);
@ -5400,22 +5407,21 @@ static void HandlePacketFromPlayer(SINT8 node)
} }
#endif #endif
// Don't leak uninitialized memory.
memset(&netbuffer->u.responseall, 0, sizeof(netbuffer->u.responseall)); memset(&netbuffer->u.responseall, 0, sizeof(netbuffer->u.responseall));
for (challengeplayers = 0; challengeplayers <= splitscreen; challengeplayers++) for (challengeplayers = 0; challengeplayers <= splitscreen; challengeplayers++)
{ {
uint8_t signature[64]; uint8_t signature[64];
profile_t *localProfile = PR_GetLocalPlayerProfile(challengeplayers); profile_t *localProfile = PR_GetLocalPlayerProfile(challengeplayers);
if (PR_IsLocalPlayerGuest(challengeplayers)) // GUESTS don't have keys if (!PR_IsLocalPlayerGuest(challengeplayers)) // GUESTS don't have keys
{
memset(signature, 0, 64);
}
else
{ {
CONS_Printf("signing %s pk %s\n", GetPrettyRRID(lastChallengeAll, true), GetPrettyRRID(localProfile->public_key, true)); CONS_Printf("signing %s pk %s\n", GetPrettyRRID(lastChallengeAll, true), GetPrettyRRID(localProfile->public_key, true));
crypto_eddsa_sign(signature, localProfile->secret_key, lastChallengeAll, sizeof(lastChallengeAll)); crypto_eddsa_sign(signature, localProfile->secret_key, lastChallengeAll, sizeof(lastChallengeAll));
// If our keys are garbage (corrupted profile?), fail here instead of when the server boots us, so the player knows what's going on.
if (crypto_eddsa_check(signature, localProfile->public_key, lastChallengeAll, sizeof(lastChallengeAll)) != 0) if (crypto_eddsa_check(signature, localProfile->public_key, lastChallengeAll, sizeof(lastChallengeAll)) != 0)
I_Error("Couldn't self-verify key associated with player %d, profile %d.\nProfile data may be corrupted.", challengeplayers, cv_lastprofile[challengeplayers].value); // I guess this is the most reasonable way to catch a malformed key. I_Error("Couldn't self-verify key associated with player %d, profile %d.\nProfile data may be corrupted.", challengeplayers, cv_lastprofile[challengeplayers].value);
} }
#ifdef DEVELOP #ifdef DEVELOP
@ -5437,28 +5443,20 @@ static void HandlePacketFromPlayer(SINT8 node)
break; break;
int responseplayer; int responseplayer;
//CONS_Printf("Got PT_RESPONSEALL from node %d, player %d\n", node, nodetoplayer[node]);
for (responseplayer = 0; responseplayer < MAXSPLITSCREENPLAYERS; responseplayer++) for (responseplayer = 0; responseplayer < MAXSPLITSCREENPLAYERS; responseplayer++)
{ {
int targetplayer = NodeToSplitPlayer(node, responseplayer); int targetplayer = NodeToSplitPlayer(node, responseplayer);
if (targetplayer == -1) if (targetplayer == -1)
continue; continue;
if (IsSplitPlayerOnNodeGuest(node, responseplayer)) if (!IsPlayerGuest(targetplayer))
{
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)); 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], if (crypto_eddsa_check(netbuffer->u.responseall.signature[responseplayer], players[targetplayer].public_key, lastChallengeAll, sizeof(lastChallengeAll)))
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); CONS_Alert(CONS_WARNING, "Invalid PT_RESPONSEALL from node %d player %d split %d\n", node, targetplayer, responseplayer);
if (playernode[targetplayer] != 0) // NO IDEA. if (playernode[targetplayer] != 0) // NO IDEA.
{
SendKick(targetplayer, KICK_MSG_SIGFAIL); SendKick(targetplayer, KICK_MSG_SIGFAIL);
}
break; break;
} }
else else
@ -5500,6 +5498,8 @@ static void HandlePacketFromPlayer(SINT8 node)
} }
else if (memcmp(knownWhenChallenged[resultsplayer], players[resultsplayer].public_key, sizeof(knownWhenChallenged[resultsplayer])) != 0) else if (memcmp(knownWhenChallenged[resultsplayer], players[resultsplayer].public_key, sizeof(knownWhenChallenged[resultsplayer])) != 0)
{ {
// A player left after the challenge process started, and someone else took their place.
// That means haven't received a challenge either.
CONS_Printf("Has key %s but I remember key %s - node %d player %d split %d, not enforcing\n", CONS_Printf("Has key %s but I remember key %s - node %d player %d split %d, not enforcing\n",
GetPrettyRRID(knownWhenChallenged[resultsplayer], true), GetPrettyRRID(players[resultsplayer].public_key, true), GetPrettyRRID(knownWhenChallenged[resultsplayer], true), GetPrettyRRID(players[resultsplayer].public_key, true),
playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex); playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex);
@ -5511,7 +5511,7 @@ static void HandlePacketFromPlayer(SINT8 node)
knownWhenChallenged[resultsplayer], lastChallengeAll, sizeof(lastChallengeAll))) knownWhenChallenged[resultsplayer], lastChallengeAll, sizeof(lastChallengeAll)))
{ {
CONS_Alert(CONS_WARNING, "PT_RESULTSALL had invalid signature %s for node %d player %d split %d, something doesn't add up!\n", CONS_Alert(CONS_WARNING, "PT_RESULTSALL had invalid signature %s for node %d player %d split %d, something doesn't add up!\n",
GetPrettyRRID(netbuffer->u.resultsall.signature[resultsplayer], true), playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex); GetPrettyRRID(netbuffer->u.resultsall.signature[resultsplayer], true), playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex);
HandleSigfail("Server sent invalid client signature."); HandleSigfail("Server sent invalid client signature.");
break; break;
} }
@ -6338,151 +6338,174 @@ static void UpdatePingTable(void)
} }
} }
static void UpdateChallenges(void) // It's that time again! Send everyone a safe message to sign, so we can show off their signature and prove we're playing fair.
static void SendChallenges(void)
{ {
int i; int i;
if (server) netbuffer->packettype = PT_CHALLENGEALL;
#ifdef DEVELOP
if (cv_nochallenge.value)
{
CV_AddValue(&cv_nochallenge, -1);
CONS_Alert(CONS_WARNING, "cv_nochallenge enabled, not sending PT_CHALLENGEALL\n");
return;
}
#endif
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
GenerateChallenge(netbuffer->u.challengeall.secret);
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
memset(lastReceivedSignature, 0, sizeof(lastReceivedSignature));
for (i = 0; i < MAXNETNODES; i++)
{ {
if (Playing() && (leveltime == CHALLENGEALL_START)) if (nodeingame[i])
{ {
netbuffer->packettype = PT_CHALLENGEALL; CONS_Printf("challenge to node %d, player %d\n", i, nodetoplayer[i]);
HSendPacket(i, true, 0, sizeof(challengeall_pak));
#ifdef DEVELOP memcpy(knownWhenChallenged[nodetoplayer[i]], players[nodetoplayer[i]].public_key, sizeof(knownWhenChallenged[nodetoplayer[i]]));
if (cv_nochallenge.value)
{
CV_AddValue(&cv_nochallenge, -1);
CONS_Alert(CONS_WARNING, "cv_nochallenge enabled, not sending PT_CHALLENGEALL\n");
return;
}
#endif
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
GenerateChallenge(netbuffer->u.challengeall.secret);
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
memset(lastReceivedSignature, 0, sizeof(lastReceivedSignature));
for (i = 0; i < MAXNETNODES; i++)
{
if (nodeingame[i])
{
CONS_Printf("challenge to node %d, player %d\n", i, nodetoplayer[i]);
HSendPacket(i, true, 0, sizeof(challengeall_pak));
memcpy(knownWhenChallenged[nodetoplayer[i]], players[nodetoplayer[i]].public_key, sizeof(knownWhenChallenged[nodetoplayer[i]]));
}
}
} }
}
}
if (Playing() && (leveltime == CHALLENGEALL_KICKUNRESPONSIVE)) // Before we start sending out the results, we need to kick everyone who didn't respond.
// (If we try to do both at once, clients will still see players who failled in-game when the results arrive...)
static void KickUnverifiedPlayers(void)
{
int i;
uint8_t allZero[64];
memset(allZero, 0, sizeof(allZero));
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (memcmp(lastReceivedSignature[i], allZero, sizeof(allZero)) == 0) // We never got a response!
{ {
uint8_t allZero[64]; if (!IsPlayerGuest(i) && memcmp(knownWhenChallenged[i], players[i].public_key, sizeof(knownWhenChallenged[i]) == 0))
memset(allZero, 0, sizeof(allZero));
for (i = 0; i < MAXPLAYERS; i++)
{ {
if (!playeringame[i]) if (playernode[i] != servernode)
continue;
if (memcmp(lastReceivedSignature[i], allZero, sizeof(allZero)) == 0) // We never got a response!
{ {
if (!IsPlayerGuest(i) && memcmp(knownWhenChallenged[i], players[i].public_key, sizeof(knownWhenChallenged[i]) == 0)) CONS_Printf("We never got a response from player %d, goodbye\n", i);
{ SendKick(i, KICK_MSG_SIGFAIL);
if (playernode[i] != servernode)
{
CONS_Printf("We never got a response from player %d, goodbye\n", i);
SendKick(i, KICK_MSG_SIGFAIL);
}
}
}
}
}
if (Playing() && (leveltime == CHALLENGEALL_SENDRESULTS))
{
netbuffer->packettype = PT_RESULTSALL;
#ifdef DEVELOP
if (cv_noresults.value)
{
CV_AddValue(&cv_noresults, -1);
CONS_Alert(CONS_WARNING, "cv_noresults enabled, not sending PT_RESULTSALL\n");
return;
}
#endif
uint8_t allZero[64];
memset(allZero, 0, sizeof(allZero));
memset(&netbuffer->u.resultsall, 0, sizeof(netbuffer->u.resultsall));
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (memcmp(lastReceivedSignature[i], allZero, sizeof(allZero)) == 0) // We never got a response!
{
if (!IsPlayerGuest(i))
CONS_Alert(CONS_WARNING, "Unreceived signature for player %d, who is still in-game\n", i);
}
else
{
CONS_Printf("Player %d passed with key %s sig %s, adding...\n", i, GetPrettyRRID(players[i].public_key, true), GetPrettyRRID(lastReceivedSignature[i], true));
memcpy(netbuffer->u.resultsall.signature[i], lastReceivedSignature[i], sizeof(netbuffer->u.resultsall.signature[i]));
#ifdef DEVELOP
if (cv_badresults.value)
{
CV_AddValue(&cv_badresults, -1);
CONS_Alert(CONS_WARNING, "cv_badresults enabled, scrubbing signature from PT_RESULTSALL\n");
memset(netbuffer->u.resultsall.signature[i], 0, sizeof(netbuffer->u.resultsall.signature[i]));
}
#endif
}
}
for (i = 0; i < MAXPLAYERS; i++)
{
CONS_Printf("SIG %d: %s\n", i, GetPrettyRRID(netbuffer->u.resultsall.signature[i], true));
}
for (i = 0; i < MAXNETNODES; i++)
{
if (nodeingame[i])
{
CONS_Printf("results to node %d, player %d\n", i, nodetoplayer[i]);
HSendPacket(i, true, 0, sizeof(resultsall_pak));
} }
} }
} }
} }
else }
{
if (Playing() && (leveltime == CHALLENGEALL_START)) //
static void SendChallengeResults(void)
{
int i;
netbuffer->packettype = PT_RESULTSALL;
#ifdef DEVELOP
if (cv_noresults.value)
{ {
// Who should we try to verify when results come in? CV_AddValue(&cv_noresults, -1);
// Store a public key for every active slot, so if players shuffle during challenge leniency, CONS_Alert(CONS_WARNING, "cv_noresults enabled, not sending PT_RESULTSALL\n");
// we don't incorrectly try to verify someone who didn't even get a challenge, throw a tantrum, and bail. return;
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
{
//CONS_Printf("Player %i isn't present for checkall\n", i);
continue;
}
else if (IsPlayerGuest(i))
{
//CONS_Printf("Player %i is present for checkall, but is a guest\n", i);
continue;
}
else
{
CONS_Printf("Player %d (node %d split %d) is present for checkall, make a note of their key %s...\n", i, playernode[i], players[i].splitscreenindex,
GetPrettyRRID(players[i].public_key, true));
memcpy(knownWhenChallenged[i], players[i].public_key, sizeof(knownWhenChallenged[i]));
}
}
} }
#endif
uint8_t allZero[64];
memset(allZero, 0, sizeof(allZero));
memset(&netbuffer->u.resultsall, 0, sizeof(netbuffer->u.resultsall));
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// Don't try to transmit signatures for players who didn't get here in time to send one.
// (Everyone who had their chance should have been kicked by KickUnverifiedPlayers by now.)
if (memcmp(lastReceivedSignature[i], allZero, sizeof(allZero)) == 0)
continue;
CONS_Printf("Player %d passed with key %s sig %s, adding...\n", i, GetPrettyRRID(players[i].public_key, true), GetPrettyRRID(lastReceivedSignature[i], true));
memcpy(netbuffer->u.resultsall.signature[i], lastReceivedSignature[i], sizeof(netbuffer->u.resultsall.signature[i]));
#ifdef DEVELOP
if (cv_badresults.value)
{
CV_AddValue(&cv_badresults, -1);
CONS_Alert(CONS_WARNING, "cv_badresults enabled, scrubbing signature from PT_RESULTSALL\n");
memset(netbuffer->u.resultsall.signature[i], 0, sizeof(netbuffer->u.resultsall.signature[i]));
}
#endif
}
for (i = 0; i < MAXNETNODES; i++)
{
if (nodeingame[i])
{
CONS_Printf("results to node %d, player %d\n", i, nodetoplayer[i]);
HSendPacket(i, true, 0, sizeof(resultsall_pak));
}
}
}
// Who should we try to verify when results come in?
// Store a public key for every active slot, so if players shuffle during challenge leniency,
// we don't incorrectly try to verify someone who didn't even get a challenge, throw a tantrum, and bail.
static void CheckPresentPlayers(void)
{
int i;
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
{
//CONS_Printf("Player %i isn't present for checkall\n", i);
continue;
}
else if (IsPlayerGuest(i))
{
//CONS_Printf("Player %i is present for checkall, but is a guest\n", i);
continue;
}
else
{
CONS_Printf("Player %d (node %d split %d) is present for checkall, make a note of their key %s...\n", i, playernode[i], players[i].splitscreenindex,
GetPrettyRRID(players[i].public_key, true));
memcpy(knownWhenChallenged[i], players[i].public_key, sizeof(knownWhenChallenged[i]));
}
}
}
// Handle "client-to-client" auth challenge flow.
static void UpdateChallenges(void)
{
if (!(Playing() && netgame))
return;
if (server)
{
if (leveltime == CHALLENGEALL_START)
SendChallenges();
if (leveltime == CHALLENGEALL_KICKUNRESPONSIVE)
KickUnverifiedPlayers();
if (leveltime == CHALLENGEALL_SENDRESULTS)
SendChallengeResults();
}
else // client
{
if (leveltime <= CHALLENGEALL_START)
expectChallenge = true;
if (leveltime == CHALLENGEALL_START)
CheckPresentPlayers();
if (leveltime > CHALLENGEALL_CLIENTCUTOFF && expectChallenge)
HandleSigfail("Didn't receive client signatures.");
} }
} }
@ -6531,8 +6554,7 @@ void NetKeepAlive(void)
UpdatePingTable(); UpdatePingTable();
if (netgame) UpdateChallenges();
UpdateChallenges();
GetPackets(); GetPackets();

View file

@ -422,11 +422,11 @@ struct doomdata_t
INT32 filesneedednum; // 4 bytes INT32 filesneedednum; // 4 bytes
filesneededconfig_pak filesneededcfg; // ??? bytes filesneededconfig_pak filesneededcfg; // ??? bytes
UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes UINT32 pingtable[MAXPLAYERS+1]; // 68 bytes
clientkey_pak clientkey; // TODO: Tyron, does anyone take any of these sizes even remotely seriously clientkey_pak clientkey; // 32 bytes
serverchallenge_pak serverchallenge; // Are you even going to update this shit, are you even going to remove this comment serverchallenge_pak serverchallenge; // 64 bytes
challengeall_pak challengeall; challengeall_pak challengeall; // 256 bytes
responseall_pak responseall; responseall_pak responseall; // 256 bytes
resultsall_pak resultsall; resultsall_pak resultsall; // 1024 bytes. Also, you really shouldn't trust anything here.
} u; // This is needed to pack diff packet types data together } u; // This is needed to pack diff packet types data together
} ATTRPACK; } ATTRPACK;
@ -501,10 +501,10 @@ extern boolean expectChallenge;
// We give clients a chance to verify each other once per race. // We give clients a chance to verify each other once per race.
// When is that challenge sent, and when should clients bail if they don't receive the responses? // When is that challenge sent, and when should clients bail if they don't receive the responses?
#define CHALLENGEALL_START (TICRATE*10) #define CHALLENGEALL_START (TICRATE*5)
#define CHALLENGEALL_KICKUNRESPONSIVE (TICRATE*12) #define CHALLENGEALL_KICKUNRESPONSIVE (TICRATE*10)
#define CHALLENGEALL_SENDRESULTS (TICRATE*14) #define CHALLENGEALL_SENDRESULTS (TICRATE*15)
#define CHALLENGEALL_CLIENTCUTOFF (TICRATE*16) #define CHALLENGEALL_CLIENTCUTOFF (TICRATE*20)
void Command_Ping_f(void); void Command_Ping_f(void);
extern tic_t connectiontimeout; extern tic_t connectiontimeout;

View file

@ -1314,6 +1314,8 @@ void PT_FileReceived(void)
SV_EndFileSend(doomcom->remotenode); SV_EndFileSend(doomcom->remotenode);
} }
// Someone knocked on the door with their public key.
// Give them a challenge to sign in their PT_CLIENTJOIN.
void PT_ClientKey(INT32 node) void PT_ClientKey(INT32 node)
{ {
clientkey_pak *packet = (void*)&netbuffer->u.clientkey; clientkey_pak *packet = (void*)&netbuffer->u.clientkey;

View file

@ -971,15 +971,6 @@ void P_Ticker(boolean run)
G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1); G_CopyTiccmd(&players[i].oldcmd, &players[i].cmd, 1);
} }
if (leveltime <= CHALLENGEALL_START && client)
expectChallenge = true;
if (leveltime > CHALLENGEALL_CLIENTCUTOFF && expectChallenge && client)
{
HandleSigfail("Didn't receive client signatures.");
return;
}
// Z_CheckMemCleanup(); // Z_CheckMemCleanup();
} }