RRID port part 3
last commit was 535fc1787589cc8135470cef0e09005cf97e6cab
This commit is contained in:
parent
5bafcbf3f8
commit
0857a1d8a2
13 changed files with 151 additions and 140 deletions
|
|
@ -1655,6 +1655,38 @@ freely, subject to the following restrictions:
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2-Clause BSD License
|
||||
applies to:
|
||||
- monocypher
|
||||
Copyright (c) 2017-2020, Loup Vaillant
|
||||
All rights reserved.
|
||||
https://monocypher.org/
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
MIT License
|
||||
applies to:
|
||||
|
|
|
|||
171
src/d_clisrv.c
171
src/d_clisrv.c
|
|
@ -187,20 +187,19 @@ char connectedserverdescription[MAXSERVERDESCRIPTION];
|
|||
boolean acceptnewnode = true;
|
||||
|
||||
UINT32 ourIP; // Used when populating PT_SERVERCHALLENGE (guards against signature reuse)
|
||||
uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][32]; // Player's public key (join process only! active players have it on player_t)
|
||||
uint8_t lastSentChallenge[MAXNETNODES][32]; // The random message we asked them to sign in PT_SERVERCHALLENGE, check it in PT_CLIENTJOIN
|
||||
uint8_t lastChallengeAll[64]; // The message we asked EVERYONE to sign for client-to-client identity proofs
|
||||
uint8_t lastReceivedSignature[MAXPLAYERS][64]; // Everyone's response to lastChallengeAll
|
||||
uint8_t knownWhenChallenged[MAXPLAYERS][32]; // Everyone a client saw at the moment a challenge should be initiated
|
||||
uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][PUBKEYLENGTH]; // Player's public key (join process only! active players have it on player_t)
|
||||
uint8_t lastSentChallenge[MAXNETNODES][CHALLENGELENGTH]; // The random message we asked them to sign in PT_SERVERCHALLENGE, check it in PT_CLIENTJOIN
|
||||
uint8_t awaitingChallenge[CHALLENGELENGTH]; // The message the server asked our client to sign when joining
|
||||
uint8_t lastChallengeAll[CHALLENGELENGTH]; // The message we asked EVERYONE to sign for client-to-client identity proofs
|
||||
uint8_t lastReceivedSignature[MAXPLAYERS][SIGNATURELENGTH]; // Everyone's response to lastChallengeAll
|
||||
uint8_t knownWhenChallenged[MAXPLAYERS][PUBKEYLENGTH]; // 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?
|
||||
|
||||
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
|
||||
uint8_t priorKeys[MAXPLAYERS][PUBKEYLENGTH]; // 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
|
||||
tic_t firstconnectattempttime = 0;
|
||||
|
||||
uint8_t awaitingChallenge[32];
|
||||
|
||||
#ifdef DEVELOP
|
||||
consvar_t cv_badjoin = CVAR_INIT ("badjoin", "0", 0, CV_Unsigned, NULL);
|
||||
consvar_t cv_badtraffic = CVAR_INIT ("badtraffic", "0", 0, CV_Unsigned, NULL);
|
||||
|
|
@ -254,35 +253,15 @@ consvar_t cv_kicktime = CVAR_INIT ("kicktime", "10", CV_SAVE, CV_Unsigned, NULL)
|
|||
|
||||
static tic_t stop_spamming[MAXPLAYERS];
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a message for an authenticating client to sign, with some guarantees about who we are.
|
||||
void GenerateChallenge(uint8_t *buf)
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
csprng(buf, sizeof(&buf)); // Random noise as a baseline, but...
|
||||
#ifndef SRB2_LITTLE_ENDIAN
|
||||
#error "FIXME: 64-bit timestamp field is not supported on Big Endian"
|
||||
#endif
|
||||
|
||||
UINT64 now = time(NULL);
|
||||
csprng(buf, CHALLENGELENGTH); // Random noise as a baseline, but...
|
||||
memcpy(buf, &now, sizeof(now)); // Timestamp limits the reuse window.
|
||||
memcpy(buf + sizeof(now), &ourIP, sizeof(ourIP)); // IP prevents captured signatures from being used elsewhere.
|
||||
|
||||
|
|
@ -307,19 +286,22 @@ void GenerateChallenge(uint8_t *buf)
|
|||
// Don't sign anything that wasn't generated just for us!
|
||||
shouldsign_t ShouldSignChallenge(uint8_t *message)
|
||||
{
|
||||
time_t then, now;
|
||||
#ifndef SRB2_LITTLE_ENDIAN
|
||||
#error "FIXME: 64-bit timestamp field is not supported on Big Endian"
|
||||
#endif
|
||||
|
||||
UINT64 then, now;
|
||||
UINT32 claimedIP, realIP;
|
||||
|
||||
now = time(NULL);
|
||||
memcpy(&then, message, sizeof(then));
|
||||
memcpy(&claimedIP, message + sizeof(then), sizeof(claimedIP));
|
||||
CONS_Printf("servernode: %d\n", servernode);
|
||||
realIP = I_GetNodeAddressInt(servernode);
|
||||
|
||||
if (abs(now - then) > 60*5)
|
||||
if ((max(now, then) - min(now, then)) > 60*5)
|
||||
return SIGN_BADTIME;
|
||||
|
||||
if (realIP != claimedIP && IsExternalAddress(&realIP))
|
||||
if (realIP != claimedIP && I_IsExternalAddress(&realIP))
|
||||
return SIGN_BADIP;
|
||||
|
||||
return SIGN_OK;
|
||||
|
|
@ -1033,11 +1015,11 @@ static boolean CL_SendJoin(void)
|
|||
|
||||
for (i = 0; i <= splitscreen; i++)
|
||||
{
|
||||
uint8_t signature[64];
|
||||
uint8_t signature[SIGNATURELENGTH];
|
||||
|
||||
// If our keys are garbage (corrupted profile?), fail here instead of when the server boots us, so the player knows what's going on.
|
||||
crypto_eddsa_sign(signature, secret_key[i], awaitingChallenge, 32);
|
||||
if (crypto_eddsa_check(signature, public_key[i], awaitingChallenge, 32) != 0)
|
||||
crypto_eddsa_sign(signature, secret_key[i], awaitingChallenge, sizeof(awaitingChallenge));
|
||||
if (crypto_eddsa_check(signature, public_key[i], awaitingChallenge, sizeof(awaitingChallenge)) != 0)
|
||||
I_Error("Couldn't self-verify key associated with player %d.\nKey may be corrupted.\n", i); // I guess this is the most reasonable way to catch a malformed key.
|
||||
|
||||
#ifdef DEVELOP
|
||||
|
|
@ -1045,7 +1027,7 @@ static boolean CL_SendJoin(void)
|
|||
{
|
||||
CV_AddValue(&cv_badjoin, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badjoin enabled, scrubbing signature from CL_SendJoin\n");
|
||||
memset(signature, 0, 64);
|
||||
memset(signature, 0, sizeof(signature));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -3884,7 +3866,6 @@ static void ResetNode(INT32 node)
|
|||
nodeingame[node] = false;
|
||||
nodewaiting[node] = 0;
|
||||
nodeneedsauth[node] = false;
|
||||
//CONS_Printf("2: node %d -> %d\n", node, nodeneedsauth[node]);
|
||||
|
||||
nettics[node] = gametic;
|
||||
supposedtics[node] = gametic;
|
||||
|
|
@ -4065,7 +4046,6 @@ static inline void SV_AddNode(INT32 node)
|
|||
nodeingame[node] = true;
|
||||
|
||||
nodeneedsauth[node] = false;
|
||||
CONS_Printf("3: node %d -> %d\n", node, nodeneedsauth[node]);
|
||||
}
|
||||
|
||||
// Xcmd XD_ADDPLAYER
|
||||
|
|
@ -4099,7 +4079,7 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
|
|||
newplayer->jointime = 0;
|
||||
|
||||
READSTRINGN(*p, player_names[newplayernum], MAXPLAYERNAME);
|
||||
READSTRINGN(*p, players[newplayernum].public_key, 32);
|
||||
READMEM(*p, players[newplayernum].public_key, PUBKEYLENGTH);
|
||||
|
||||
console = READUINT8(*p);
|
||||
splitscreenplayer = READUINT8(*p);
|
||||
|
|
@ -4239,7 +4219,7 @@ const char *name, uint8_t *key, const char *name2, uint8_t *key2,
|
|||
const char *name3, uint8_t *key3, const char *name4, uint8_t *key4)
|
||||
{
|
||||
INT32 n, newplayernum, i;
|
||||
UINT8 buf[4 + MAXPLAYERNAME + 32 + MAXAVAILABILITY];
|
||||
UINT8 buf[4 + MAXPLAYERNAME + PUBKEYLENGTH + MAXAVAILABILITY];
|
||||
UINT8 *buf_p = buf;
|
||||
boolean newplayer = false;
|
||||
|
||||
|
|
@ -4302,25 +4282,25 @@ const char *name3, uint8_t *key3, const char *name4, uint8_t *key4)
|
|||
{
|
||||
nodetoplayer[node] = newplayernum;
|
||||
WRITESTRINGN(buf_p, name, MAXPLAYERNAME);
|
||||
WRITESTRINGN(buf_p, key, 32);
|
||||
WRITEMEM(buf_p, key, PUBKEYLENGTH);
|
||||
}
|
||||
else if (playerpernode[node] < 2)
|
||||
{
|
||||
nodetoplayer2[node] = newplayernum;
|
||||
WRITESTRINGN(buf_p, name2, MAXPLAYERNAME);
|
||||
WRITESTRINGN(buf_p, key2, 32);
|
||||
WRITEMEM(buf_p, key2, PUBKEYLENGTH);
|
||||
}
|
||||
else if (playerpernode[node] < 3)
|
||||
{
|
||||
nodetoplayer3[node] = newplayernum;
|
||||
WRITESTRINGN(buf_p, name3, MAXPLAYERNAME);
|
||||
WRITESTRINGN(buf_p, key3, 32);
|
||||
WRITEMEM(buf_p, key3, PUBKEYLENGTH);
|
||||
}
|
||||
else if (playerpernode[node] < 4)
|
||||
{
|
||||
nodetoplayer4[node] = newplayernum;
|
||||
WRITESTRINGN(buf_p, name4, MAXPLAYERNAME);
|
||||
WRITESTRINGN(buf_p, key4, 32);
|
||||
WRITEMEM(buf_p, key4, PUBKEYLENGTH);
|
||||
}
|
||||
|
||||
WRITEUINT8(buf_p, nodetoplayer[node]); // consoleplayer
|
||||
|
|
@ -4598,8 +4578,6 @@ static void HandleConnect(SINT8 node)
|
|||
UINT8 maxplayers = min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value);
|
||||
UINT8 connectedplayers = 0;
|
||||
|
||||
CONS_Printf(">>>> node %d (%s)\n", node, I_GetNodeAddress(node));
|
||||
|
||||
for (i = dedicated ? 1 : 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
// We use this to count players because it is affected by SV_AddWaitingPlayers when
|
||||
|
|
@ -4723,9 +4701,7 @@ static void HandleConnect(SINT8 node)
|
|||
}
|
||||
else // Remote player, gotta check their signature.
|
||||
{
|
||||
CONS_Printf("Adding remote. Doing sigcheck for node %d, ID %s\n", node, GetPrettyRRID(lastReceivedKey[i][node], true));
|
||||
|
||||
sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse[i], lastReceivedKey[node][i], lastSentChallenge[node], 32);
|
||||
sigcheck = crypto_eddsa_check(netbuffer->u.clientcfg.challengeResponse[i], lastReceivedKey[node][i], lastSentChallenge[node], CHALLENGELENGTH);
|
||||
|
||||
if (netgame && sigcheck != 0)
|
||||
{
|
||||
|
|
@ -5482,7 +5458,6 @@ static void PT_ClientQuit(SINT8 node, INT32 netconsole)
|
|||
Net_CloseConnection(node);
|
||||
nodeingame[node] = false;
|
||||
nodeneedsauth[node] = false;
|
||||
CONS_Printf("1: node %d -> %d\n", node, nodeneedsauth[node]);
|
||||
}
|
||||
|
||||
static void PT_CanReceiveGamestate(SINT8 node)
|
||||
|
|
@ -5856,13 +5831,6 @@ static void HandlePacketFromAwayNode(SINT8 node)
|
|||
// Otherwise, someone else could request a challenge on the same node and trash it.
|
||||
nodeneedsauth[node] = true;
|
||||
freezetimeout[node] = I_GetTime() + jointimeout;
|
||||
|
||||
CONS_Printf("4: node %d -> %d\n", node, nodeneedsauth[node]);
|
||||
if (nodeneedsauth[node] == false)
|
||||
{
|
||||
freezetimeout[node] = I_GetTime() + jointimeout;
|
||||
nodeneedsauth[node] = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PT_SERVERCHALLENGE:
|
||||
|
|
@ -5944,7 +5912,10 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
netbuffer->packettype, node, splitnodes,
|
||||
GetPrettyRRID(players[targetplayer].public_key, true), doomcom->datalength - BASEPACKETSIZE, netconsole);
|
||||
|
||||
if (netconsole != -1) // NO IDEA.
|
||||
// Something scary can happen when multiple kicks that resolve to the same node are processed in quick succession.
|
||||
// Sometimes, a kick will still be left to process after the player's been disposed, and that causes the kick to resolve on the server instead!
|
||||
// This sucks, so we check for a stale/misfiring kick beforehand.
|
||||
if (netconsole != -1)
|
||||
SendKick(netconsole, KICK_MSG_SIGFAIL);
|
||||
Net_CloseConnection(node);
|
||||
nodeingame[node] = false;
|
||||
|
|
@ -5995,7 +5966,7 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
case PT_WILLRESENDGAMESTATE: PT_WillResendGamestate(node ); break;
|
||||
case PT_SENDINGLUAFILE : PT_SendingLuaFile (node ); break;
|
||||
case PT_SERVERCFG : break;
|
||||
case PT_CHALLENGEALL: ; // -Wpedantic
|
||||
case PT_CHALLENGEALL: ;
|
||||
if (demo.playback || node != servernode) // SERVER should still respond to this to prove its own identity, just not from clients.
|
||||
break;
|
||||
|
||||
|
|
@ -6031,8 +6002,7 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
|
||||
for (challengeplayers = 0; challengeplayers <= splitscreen; challengeplayers++)
|
||||
{
|
||||
uint8_t signature[64];
|
||||
CONS_Printf("signing %s pk %s\n", GetPrettyRRID(lastChallengeAll, true), GetPrettyRRID(public_key[challengeplayers], true));
|
||||
uint8_t signature[SIGNATURELENGTH];
|
||||
|
||||
crypto_eddsa_sign(signature, secret_key[challengeplayers], lastChallengeAll, sizeof(lastChallengeAll));
|
||||
if (crypto_eddsa_check(signature, public_key[challengeplayers], lastChallengeAll, sizeof(lastChallengeAll)) != 0)
|
||||
|
|
@ -6043,7 +6013,7 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
{
|
||||
CV_AddValue(&cv_badresponse, -1);
|
||||
CONS_Alert(CONS_WARNING, "cv_badresponse enabled, scrubbing signature from PT_RESPONSEALL\n");
|
||||
memset(signature, 0, 64);
|
||||
memset(signature, 0, sizeof(signature));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -6066,49 +6036,42 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
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.
|
||||
// Something scary can happen when multiple kicks that resolve to the same node are processed in quick succession.
|
||||
// Sometimes, a kick will still be left to process after the player's been disposed, and that causes the kick to resolve on the server instead!
|
||||
// This sucks, so we check for a stale/misfiring kick beforehand.
|
||||
if (playernode[targetplayer] != 0)
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PT_RESULTSALL: ; // -Wpedantic
|
||||
int resultsplayer;
|
||||
uint8_t allzero[64];
|
||||
memset(allzero, 0, sizeof(allzero));
|
||||
|
||||
CONS_Printf("Got PT_RESULTSALL\n");
|
||||
|
||||
case PT_RESULTSALL:
|
||||
if (demo.playback || server || node != servernode || !expectChallenge)
|
||||
break;
|
||||
|
||||
CONS_Printf("Checking PT_RESULTSALL\n");
|
||||
int resultsplayer;
|
||||
uint8_t allZero[PUBKEYLENGTH];
|
||||
memset(allZero, 0, sizeof(PUBKEYLENGTH));
|
||||
|
||||
for (resultsplayer = 0; resultsplayer < MAXPLAYERS; resultsplayer++)
|
||||
{
|
||||
if (!playeringame[resultsplayer])
|
||||
{
|
||||
CONS_Printf("Player %d isn't in the game, excluded from checkall\n", resultsplayer);
|
||||
continue;
|
||||
}
|
||||
else if (memcmp(knownWhenChallenged[resultsplayer], allzero, sizeof(allzero)) == 0)
|
||||
else if (memcmp(knownWhenChallenged[resultsplayer], allZero, sizeof(PUBKEYLENGTH)) == 0)
|
||||
{
|
||||
CONS_Printf("That motherfucker wasn't here for the challenge - node %d player %d split %d, not enforcing\n", playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex);
|
||||
// Wasn't here for the challenge.
|
||||
continue;
|
||||
}
|
||||
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 they 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",
|
||||
GetPrettyRRID(knownWhenChallenged[resultsplayer], true), GetPrettyRRID(players[resultsplayer].public_key, true),
|
||||
playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -6121,10 +6084,6 @@ static void HandlePacketFromPlayer(SINT8 node)
|
|||
HandleSigfail("Server sent invalid client signature.");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf("Checkall client-pass for node %d player %d split %d\n", playernode[resultsplayer], resultsplayer, players[resultsplayer].splitscreenindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
csprng(lastChallengeAll, sizeof(lastChallengeAll));
|
||||
|
|
@ -7161,20 +7120,22 @@ static void SendChallenges(void)
|
|||
#endif
|
||||
|
||||
memset(knownWhenChallenged, 0, sizeof(knownWhenChallenged));
|
||||
memset(lastReceivedSignature, 0, sizeof(lastReceivedSignature));
|
||||
|
||||
GenerateChallenge(netbuffer->u.challengeall.secret);
|
||||
memcpy(lastChallengeAll, netbuffer->u.challengeall.secret, sizeof(lastChallengeAll));
|
||||
|
||||
memset(lastReceivedSignature, 0, sizeof(lastReceivedSignature));
|
||||
// Take note of everyone's current key, so that players who disconnect and are replaced aren't held to the old player's challenge.
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
memcpy(knownWhenChallenged[i], players[i].public_key, sizeof(knownWhenChallenged[i]));
|
||||
}
|
||||
|
||||
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]]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7183,24 +7144,19 @@ static void SendChallenges(void)
|
|||
static void KickUnverifiedPlayers(void)
|
||||
{
|
||||
int i;
|
||||
uint8_t allZero[64];
|
||||
memset(allZero, 0, sizeof(allZero));
|
||||
|
||||
CONS_Printf("KickUnverifiedPlayers start\n");
|
||||
uint8_t allZero[SIGNATURELENGTH];
|
||||
memset(allZero, 0, SIGNATURELENGTH);
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i])
|
||||
continue;
|
||||
if (memcmp(lastReceivedSignature[i], allZero, sizeof(allZero)) == 0) // We never got a response!
|
||||
if (memcmp(lastReceivedSignature[i], allZero, SIGNATURELENGTH) == 0) // We never got a response!
|
||||
{
|
||||
CONS_Printf("No sig from %d\n", i);
|
||||
CONS_Printf("pk then %s, pk now %s\n", GetPrettyRRID(knownWhenChallenged[i], true), GetPrettyRRID(players[i].public_key, true));
|
||||
if (memcmp(&knownWhenChallenged[i], &players[i].public_key, sizeof(knownWhenChallenged[i])) == 0)
|
||||
{
|
||||
if (playernode[i] != servernode)
|
||||
{
|
||||
CONS_Printf("We never got a response from player %d, goodbye\n", i);
|
||||
SendKick(i, KICK_MSG_SIGFAIL);
|
||||
}
|
||||
}
|
||||
|
|
@ -7224,7 +7180,7 @@ static void SendChallengeResults(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
uint8_t allZero[64];
|
||||
uint8_t allZero[SIGNATURELENGTH];
|
||||
memset(allZero, 0, sizeof(allZero));
|
||||
|
||||
memset(&netbuffer->u.resultsall, 0, sizeof(netbuffer->u.resultsall));
|
||||
|
|
@ -7236,10 +7192,9 @@ static void SendChallengeResults(void)
|
|||
|
||||
// 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)
|
||||
if (memcmp(lastReceivedSignature[i], allZero, SIGNATURELENGTH) == 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)
|
||||
|
|
@ -7254,10 +7209,7 @@ static void SendChallengeResults(void)
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7273,13 +7225,10 @@ static void CheckPresentPlayers(void)
|
|||
{
|
||||
if (!playeringame[i])
|
||||
{
|
||||
//CONS_Printf("Player %i isn't present for checkall\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]));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ struct clientconfig_pak
|
|||
UINT8 mode;
|
||||
char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME];
|
||||
UINT8 availabilities[MAXAVAILABILITY];
|
||||
uint8_t challengeResponse[MAXSPLITSCREENPLAYERS][64];
|
||||
uint8_t challengeResponse[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
#define SV_SPEEDMASK 0x03 // used to send kartspeed
|
||||
|
|
@ -401,27 +401,27 @@ struct reqmapqueue_pak
|
|||
|
||||
struct clientkey_pak
|
||||
{
|
||||
uint8_t key[MAXSPLITSCREENPLAYERS][32];
|
||||
uint8_t key[MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
struct serverchallenge_pak
|
||||
{
|
||||
uint8_t secret[32];
|
||||
uint8_t secret[CHALLENGELENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
struct challengeall_pak
|
||||
{
|
||||
uint8_t secret[64];
|
||||
uint8_t secret[CHALLENGELENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
struct responseall_pak
|
||||
{
|
||||
uint8_t signature[MAXSPLITSCREENPLAYERS][64];
|
||||
uint8_t signature[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
struct resultsall_pak
|
||||
{
|
||||
uint8_t signature[MAXPLAYERS][64];
|
||||
uint8_t signature[MAXPLAYERS][SIGNATURELENGTH];
|
||||
} ATTRPACK;
|
||||
|
||||
struct netinfo_pak
|
||||
|
|
@ -450,7 +450,7 @@ struct doomdata_t
|
|||
|
||||
UINT8 packettype;
|
||||
#ifdef SIGNGAMETRAFFIC
|
||||
uint8_t signature[MAXSPLITSCREENPLAYERS][64];
|
||||
uint8_t signature[MAXSPLITSCREENPLAYERS][SIGNATURELENGTH];
|
||||
#endif
|
||||
UINT8 packetindex;
|
||||
union
|
||||
|
|
@ -480,7 +480,7 @@ struct doomdata_t
|
|||
say_pak say;
|
||||
reqmapqueue_pak reqmapqueue; // Formerly XD_REQMAPQUEUE
|
||||
clientkey_pak clientkey; // 32 bytes
|
||||
serverchallenge_pak serverchallenge; // 64 bytes
|
||||
serverchallenge_pak serverchallenge; // 256 bytes
|
||||
challengeall_pak challengeall; // 256 bytes
|
||||
responseall_pak responseall; // 256 bytes
|
||||
resultsall_pak resultsall; // 1024 bytes. Also, you really shouldn't trust anything here.
|
||||
|
|
@ -554,11 +554,11 @@ extern char connectedservercontact[MAXSERVERCONTACT];
|
|||
extern char connectedserverdescription[MAXSERVERDESCRIPTION];
|
||||
|
||||
extern UINT32 ourIP;
|
||||
extern uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][32];
|
||||
extern uint8_t lastSentChallenge[MAXNETNODES][32];
|
||||
extern uint8_t lastChallengeAll[64];
|
||||
extern uint8_t lastReceivedSignature[MAXPLAYERS][64];
|
||||
extern uint8_t knownWhenChallenged[MAXPLAYERS][32];
|
||||
extern uint8_t lastReceivedKey[MAXNETNODES][MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
|
||||
extern uint8_t lastSentChallenge[MAXNETNODES][CHALLENGELENGTH];
|
||||
extern uint8_t lastChallengeAll[CHALLENGELENGTH];
|
||||
extern uint8_t lastReceivedSignature[MAXPLAYERS][SIGNATURELENGTH];
|
||||
extern uint8_t knownWhenChallenged[MAXPLAYERS][PUBKEYLENGTH];
|
||||
extern boolean expectChallenge;
|
||||
|
||||
void Command_Ping_f(void);
|
||||
|
|
|
|||
|
|
@ -183,8 +183,8 @@ INT32 eventhead, eventtail;
|
|||
boolean dedicated = false;
|
||||
|
||||
// For identity negotiation with netgame servers
|
||||
uint8_t public_key[MAXSPLITSCREENPLAYERS][32];
|
||||
uint8_t secret_key[MAXSPLITSCREENPLAYERS][64];
|
||||
uint8_t public_key[MAXSPLITSCREENPLAYERS][PUBKEYLENGTH];
|
||||
uint8_t secret_key[MAXSPLITSCREENPLAYERS][PRIVKEYLENGTH];
|
||||
|
||||
boolean loaded_config = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ boolean (*I_SetBanAddress) (const char *address, const char *mask) = NULL;
|
|||
boolean (*I_SetBanUsername) (const char *username) = NULL;
|
||||
boolean (*I_SetBanReason) (const char *reason) = NULL;
|
||||
boolean (*I_SetUnbanTime) (time_t timestamp) = NULL;
|
||||
boolean (*I_IsExternalAddress) (const void *p) = NULL;
|
||||
bannednode_t *bannednode = NULL;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1350,8 +1350,6 @@ void PT_ClientKey(INT32 node)
|
|||
|
||||
memcpy(lastReceivedKey[node], packet->key, sizeof(lastReceivedKey[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;
|
||||
GenerateChallenge(lastSentChallenge[node]);
|
||||
|
||||
|
|
|
|||
|
|
@ -890,7 +890,7 @@ struct player_t
|
|||
boolean walltransfered;
|
||||
UINT8 walltransferboost;
|
||||
|
||||
uint8_t public_key[32];
|
||||
uint8_t public_key[PUBKEYLENGTH];
|
||||
|
||||
#ifdef HWRENDER
|
||||
fixed_t fovadd; // adjust FOV for hw rendering
|
||||
|
|
|
|||
|
|
@ -528,6 +528,12 @@ extern int compuncommitted;
|
|||
|
||||
#define MAX_VOLUME 100
|
||||
|
||||
// Crypto/RRID primitives
|
||||
#define PUBKEYLENGTH 32 // Enforced by Monocypher EdDSA
|
||||
#define PRIVKEYLENGTH 64 // Enforced by Monocypher EdDSA
|
||||
#define SIGNATURELENGTH 64 // Enforced by Monocypher EdDSA
|
||||
#define CHALLENGELENGTH 64 // Servers verify client identity by giving them messages to sign. How long are these messages?
|
||||
|
||||
#ifdef HAVE_CURL
|
||||
#define MASTERSERVER
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#include "f_dscredits.hpp"
|
||||
#include "strbuf.h"
|
||||
#include "k_vote.h"
|
||||
#include "d_clisrv.h"
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
#include "discord.h"
|
||||
|
|
@ -3174,7 +3175,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
SINT8 xtralife;
|
||||
|
||||
uint8_t public_key[32];
|
||||
uint8_t public_key[PUBKEYLENGTH];
|
||||
|
||||
// SRB2kart
|
||||
INT32 itemtype;
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ extern boolean (*I_SetBanAddress) (const char *address,const char *mask);
|
|||
extern boolean (*I_SetBanUsername) (const char *username);
|
||||
extern boolean (*I_SetBanReason) (const char *reason);
|
||||
extern boolean (*I_SetUnbanTime) (time_t timestamp);
|
||||
extern boolean (*I_IsExternalAddress) (const void *p);
|
||||
|
||||
struct bannednode_t
|
||||
{
|
||||
|
|
|
|||
25
src/i_tcp.c
25
src/i_tcp.c
|
|
@ -1703,6 +1703,30 @@ static void SOCK_ClearBans(void)
|
|||
banned = NULL;
|
||||
}
|
||||
|
||||
// https://github.com/jameds/holepunch/blob/master/holepunch.c#L75
|
||||
static int SOCK_IsExternalAddress (const void *p)
|
||||
{
|
||||
const int a = ((const unsigned char*)p)[0];
|
||||
const int b = ((const unsigned char*)p)[1];
|
||||
|
||||
if (*(const UINT32*)p == (UINT32)~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;
|
||||
}
|
||||
}
|
||||
|
||||
boolean I_InitTcpNetwork(void)
|
||||
{
|
||||
char serverhostname[255];
|
||||
|
|
@ -1804,6 +1828,7 @@ boolean I_InitTcpNetwork(void)
|
|||
I_SetBanUsername = SOCK_SetBanUsername;
|
||||
I_SetBanReason = SOCK_SetBanReason;
|
||||
I_SetUnbanTime = SOCK_SetUnbanTime;
|
||||
I_IsExternalAddress = SOCK_IsExternalAddress;
|
||||
bannednode = SOCK_bannednode;
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -2590,12 +2590,12 @@ int M_RoundUp(double number)
|
|||
return (int)number;
|
||||
}
|
||||
|
||||
static char rrid_buf[256];
|
||||
|
||||
char *GetPrettyRRID(const unsigned char *bin, boolean brief)
|
||||
{
|
||||
char *out;
|
||||
size_t i;
|
||||
size_t len = 32;
|
||||
size_t len = PUBKEYLENGTH;
|
||||
|
||||
if (brief)
|
||||
len = 8;
|
||||
|
|
@ -2603,15 +2603,13 @@ char *GetPrettyRRID(const unsigned char *bin, boolean brief)
|
|||
if (bin == NULL || len == 0)
|
||||
return NULL;
|
||||
|
||||
out = (char *)malloc(len*2 + 1);
|
||||
|
||||
for (i=0; i<len; i++)
|
||||
{
|
||||
out[i*2] = "0123456789ABCDEF"[bin[i] >> 4];
|
||||
out[i*2+1] = "0123456789ABCDEF"[bin[i] & 0x0F];
|
||||
rrid_buf[i*2] = "0123456789ABCDEF"[bin[i] >> 4];
|
||||
rrid_buf[i*2+1] = "0123456789ABCDEF"[bin[i] & 0x0F];
|
||||
}
|
||||
|
||||
out[len*2] = '\0';
|
||||
rrid_buf[len*2] = '\0';
|
||||
|
||||
return out;
|
||||
return rrid_buf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -862,9 +862,9 @@ static void P_NetSyncPlayers(savebuffer_t *save)
|
|||
SYNC(players[i].itemusecooldownmax);
|
||||
|
||||
if (save->write)
|
||||
WRITESTRINGN(save->p, players[i].public_key, 32 + 1);
|
||||
WRITEMEM(save->p, players[i].public_key, PUBKEYLENGTH);
|
||||
else
|
||||
READSTRINGN(save->p, players[i].public_key, 32 + 1);
|
||||
READMEM(save->p, players[i].public_key, PUBKEYLENGTH);
|
||||
|
||||
}
|
||||
TracyCZoneEnd(__zone);
|
||||
|
|
|
|||
Loading…
Reference in a new issue