From 13a82ca079ad4546586a732d6085ccd9b377972d Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 29 Mar 2026 21:28:46 -0400 Subject: [PATCH] Port pubkey validation from RR and make it optional For more competitve servers they can enable this to prevent unfair play while letting casual servers still have flexibility --- src/d_clisrv.c | 38 +++++++++++++++++++++++++++++++++++++- src/d_netcmd.c | 4 ++++ src/doomstat.h | 1 + 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ae3cdac22..c435c2063 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4574,7 +4574,7 @@ static void HandleConnect(SINT8 node) { doomdata_t *netbuffer = DOOMCOM_DATA(doomcom); char names[MAXSPLITSCREENPLAYERS][MAXPLAYERNAME + 1]; - INT32 i; + INT32 i, j; UINT8 availabilitiesbuffer[MAXAVAILABILITY]; // Sal: Dedicated mode is INCREDIBLY hacked together. @@ -4690,6 +4690,8 @@ static void HandleConnect(SINT8 node) { int sigcheck; boolean newnode = false; + char allZero[PUBKEYLENGTH]; + memset(allZero, 0, sizeof(allZero)); for (i = 0; i < netbuffer->u.clientcfg.localplayers - playerpernode[node]; i++) { @@ -4714,6 +4716,40 @@ static void HandleConnect(SINT8 node) return; } } + + if (cv_validate_pubkey.value) + { + // Check non-GUESTS for duplicate pubkeys, they'll create nonsense stats + if (memcmp(lastReceivedKey[node][i], allZero, PUBKEYLENGTH) != 0) + { + // Players already here + for (j = 0; j < MAXPLAYERS; j++) + { + if (!playeringame[j]) + continue; + + if (memcmp(lastReceivedKey[node][i], players[j].public_key, PUBKEYLENGTH) == 0) + { + SV_SendRefuse(node, M_GetText("This server disallows\nduplicate pubkeys,\n(Did you share your keys?)")); + return; + } + } + + // Players we're trying to add + for (j = 0; j < netbuffer->u.clientcfg.localplayers - playerpernode[node]; j++) + { + if (memcmp(lastReceivedKey[node][i], allZero, PUBKEYLENGTH) == 0) + continue; + if (i == j) + continue; + if (memcmp(lastReceivedKey[node][i], lastReceivedKey[node][j], PUBKEYLENGTH) == 0) + { + SV_SendRefuse(node, M_GetText("Duplicate pubkey in local party.\n(How did you even do this?)")); + return; + } + } + } + } } memcpy(availabilitiesbuffer, netbuffer->u.clientcfg.availabilities, sizeof(availabilitiesbuffer)); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 234449009..1b0ef80d9 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -791,6 +791,9 @@ consvar_t cv_nettimeout = CVAR_INIT ("nettimeout", "210", CV_CALL|CV_SAVE, netti consvar_t cv_jointimeout = CVAR_INIT ("jointimeout", "210", CV_CALL|CV_SAVE, nettimeout_cons_t, JoinTimeout_OnChange); consvar_t cv_maxping = CVAR_INIT ("maxdelay", "20", CV_SAVE, CV_Unsigned, NULL); +consvar_t cv_validate_pubkey= CVAR_INIT ("validate_pubkey", "Off", 0, CV_OnOff, NULL); // Validate for duplicate players on Join. + + static CV_PossibleValue_t lagless_cons_t[] = {{-1, "Worst"}, {0, "Best"}, {1, "Lagless"}, {0, NULL}}; consvar_t cv_lagless = CVAR_INIT ("lagless", "Lagless", CV_SAVE|CV_NETVAR|CV_CALL, lagless_cons_t, Lagless_OnChange); @@ -1146,6 +1149,7 @@ void D_RegisterServerCommands(void) COM_AddCommand("ping", Command_Ping_f); CV_RegisterVar(&cv_nettimeout); CV_RegisterVar(&cv_jointimeout); + CV_RegisterVar(&cv_validate_pubkey); CV_RegisterVar(&cv_kicktime); CV_RegisterVar(&cv_skipmapcheck); CV_RegisterVar(&cv_sleep); diff --git a/src/doomstat.h b/src/doomstat.h index 6fa215316..043d23a39 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -778,6 +778,7 @@ extern consvar_t cv_forceskin; // force clients to use the server's skin extern consvar_t cv_downloading; // allow clients to downloading WADs. extern consvar_t cv_nettimeout; // SRB2Kart: Advanced server options menu extern consvar_t cv_jointimeout; +extern consvar_t cv_validate_pubkey; extern ticcmd_t netcmds[BACKUPTICS][MAXPLAYERS]; extern INT32 serverplayer; extern INT32 adminplayers[MAXPLAYERS];