From 512ec6c2eb5fa30b5b43177b5c891d83007b746b Mon Sep 17 00:00:00 2001 From: toaster Date: Sun, 29 Sep 2024 22:03:39 +0100 Subject: [PATCH] XD_REQMAPQUEUE --> PT_REQMAPQUEUE It was technically possible for custom clients to spoil future rounds of a tournament queued while they are connected to a server. Making it a PT direct packet to the servernode both solves this problem AND reduces irrelevant NetXCmd traffic for clients. --- src/d_clisrv.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/d_clisrv.h | 11 +++++++ src/d_netcmd.c | 81 ++++++------------------------------------------ src/d_netcmd.h | 4 +-- src/typedef.h | 1 + 5 files changed, 106 insertions(+), 74 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 30e4fe110..2e04e8a7e 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -4772,6 +4772,86 @@ static void PT_Say(int node) DoSayCommand(say.message, say.target, say.flags, say.source); } +static void PT_ReqMapQueue(int node) +{ + if (client) + return; // Only sent to servers, why are we receiving this? + + reqmapqueue_pak reqmapqueue = netbuffer->u.reqmapqueue; + + // Check for a spoofed source. + if (reqmapqueue.source == serverplayer) + { + // Servers aren't guaranteed to have a playernode, dedis exist. + if (node != servernode) + return; + } + else + { + if (playernode[reqmapqueue.source] != node) + return; + + if (!IsPlayerAdmin(reqmapqueue.source)) + { + CONS_Debug(DBG_NETPLAY,"Received illegal request map queue cmd from Player %d (%s).\n", reqmapqueue.source+1, player_names[reqmapqueue.source]); + SendKick(reqmapqueue.source, KICK_MSG_CON_FAIL); + return; + } + } + + const boolean doclear = (reqmapqueue.newgametype == ROUNDQUEUE_CLEAR); + + // The following prints will only appear when multiple clients + // attempt to affect the round queue at similar time increments + if (doclear == true) + { + if (roundqueue.size == 0) + { + // therefore this one doesn't really need a error print + // because what both players wanted was done anyways + //CONS_Alert(CONS_ERROR, "queuemap: Queue is already empty!\n"); + return; + } + } + else if (roundqueue.size >= ROUNDQUEUE_MAX) + { + CONS_Alert(CONS_ERROR, "Recieved REQMAPQUEUE, but unable to add map beyond %u\n", roundqueue.size); + + // But this one does, because otherwise it's silent failure! + // Todo print the map's name, maybe? + char rejectmsg[256]; + strlcpy(rejectmsg, "The server couldn't queue your chosen map.", 256); + SendServerNotice(reqmapqueue.source, rejectmsg); + + return; + } + + UINT8 buf[1+2+1]; + UINT8 *buf_p = buf; + + WRITEUINT8(buf_p, reqmapqueue.flags); + WRITEUINT16(buf_p, reqmapqueue.newgametype); + + WRITEUINT8(buf_p, roundqueue.size); + + // Match Got_MapQueuecmd, but with the addition of reqmapqueue.newmapnum available to us + if (doclear == true) + { + memset(&roundqueue, 0, sizeof(struct roundqueue)); + } + else + { + G_MapIntoRoundQueue( + reqmapqueue.newmapnum, + reqmapqueue.newgametype, + ((reqmapqueue.flags & 1) != 0), + false + ); + } + + SendNetXCmd(XD_MAPQUEUE, buf, buf_p - buf); +} + static char NodeToSplitPlayer(int node, int split) { if (split == 0) @@ -5117,6 +5197,9 @@ static void HandlePacketFromPlayer(SINT8 node) case PT_SAY: PT_Say(node); break; + case PT_REQMAPQUEUE: + PT_ReqMapQueue(node); + break; case PT_LOGIN: if (client) break; diff --git a/src/d_clisrv.h b/src/d_clisrv.h index 191dc0ee6..85aeb9fb4 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -135,6 +135,8 @@ typedef enum PT_SAY, // "Hey server, please send this chat message to everyone via XD_SAY" + PT_REQMAPQUEUE, // Client requesting a roundqueue operation + NUMPACKETTYPE } packettype_t; @@ -401,6 +403,14 @@ struct say_pak UINT8 source; } ATTRPACK; +struct reqmapqueue_pak +{ + UINT16 newmapnum; + UINT16 newgametype; + UINT8 flags; + UINT8 source; +} ATTRPACK; + struct netinfo_pak { UINT32 pingtable[MAXPLAYERS+1]; @@ -451,6 +461,7 @@ struct doomdata_t responseall_pak responseall; // 256 bytes resultsall_pak resultsall; // 1024 bytes. Also, you really shouldn't trust anything here. say_pak say; // I don't care anymore. + reqmapqueue_pak reqmapqueue; // Formerly XD_REQMAPQUEUE } u; // This is needed to pack diff packet types data together } ATTRPACK; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c5ec7a75a..a7be4cf15 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -109,7 +109,6 @@ static void Got_DiscordInfo(const UINT8 **cp, INT32 playernum); static void Got_ScheduleTaskcmd(const UINT8 **cp, INT32 playernum); static void Got_ScheduleClearcmd(const UINT8 **cp, INT32 playernum); static void Got_Automatecmd(const UINT8 **cp, INT32 playernum); -static void Got_RequestMapQueuecmd(const UINT8 **cp, INT32 playernum); static void Got_MapQueuecmd(const UINT8 **cp, INT32 playernum); static void Got_Cheat(const UINT8 **cp, INT32 playernum); @@ -317,7 +316,7 @@ const char *netxcmdnames[MAXNETXCMD - 1] = "SCHEDULETASK", // XD_SCHEDULETASK "SCHEDULECLEAR", // XD_SCHEDULECLEAR "AUTOMATE", // XD_AUTOMATE - "REQMAPQUEUE", // XD_REQMAPQUEUE + "", "MAPQUEUE", // XD_MAPQUEUE "CALLZVOTE", // XD_CALLZVOTE "SETZVOTE", // XD_SETZVOTE @@ -369,7 +368,6 @@ void D_RegisterServerCommands(void) RegisterNetXCmd(XD_SCHEDULETASK, Got_ScheduleTaskcmd); RegisterNetXCmd(XD_SCHEDULECLEAR, Got_ScheduleClearcmd); RegisterNetXCmd(XD_AUTOMATE, Got_Automatecmd); - RegisterNetXCmd(XD_REQMAPQUEUE, Got_RequestMapQueuecmd); RegisterNetXCmd(XD_MAPQUEUE, Got_MapQueuecmd); RegisterNetXCmd(XD_CHEAT, Got_Cheat); @@ -2937,42 +2935,26 @@ static void Command_RestartLevel(void) static void Handle_MapQueueSend(UINT16 newmapnum, UINT16 newgametype, boolean newencoremode) { - static char buf[1+2+2]; - static char *buf_p = buf; - UINT8 flags = 0; - boolean doclear = (newgametype == ROUNDQUEUE_CLEAR); CONS_Debug(DBG_GAMELOGIC, "Map queue: mapnum=%d newgametype=%d newencoremode=%d\n", newmapnum, newgametype, newencoremode); - buf_p = buf; - if (newencoremode) flags |= 1; - WRITEUINT8(buf_p, flags); - WRITEUINT16(buf_p, newgametype); + netbuffer->packettype = PT_REQMAPQUEUE; - if (client) - { - WRITEUINT16(buf_p, newmapnum); - SendNetXCmd(XD_REQMAPQUEUE, buf, buf_p - buf); - return; - } + reqmapqueue_pak *reqmapqueue = &netbuffer->u.reqmapqueue; - WRITEUINT8(buf_p, roundqueue.size); + reqmapqueue->newmapnum = newmapnum; + reqmapqueue->flags = flags; + reqmapqueue->newgametype = newgametype; + reqmapqueue->source = consoleplayer; - if (doclear == true) - { - memset(&roundqueue, 0, sizeof(struct roundqueue)); - } - else - { - G_MapIntoRoundQueue(newmapnum, newgametype, newencoremode, false); - } + HSendPacket(servernode, false, 0, sizeof(reqmapqueue_pak)); - SendNetXCmd(XD_MAPQUEUE, buf, buf_p - buf); + // See PT_ReqMapQueue and Got_MapQueuecmd for the next stages } static void Command_QueueMap_f(void) @@ -3129,51 +3111,6 @@ static void Command_QueueMap_f(void) Z_Free(mapname); } -static void Got_RequestMapQueuecmd(const UINT8 **cp, INT32 playernum) -{ - UINT8 flags; - boolean setencore; - UINT16 mapnumber, setgametype; - boolean doclear = false; - - flags = READUINT8(*cp); - - setencore = ((flags & 1) != 0); - - setgametype = READUINT16(*cp); - - mapnumber = READUINT16(*cp); - - if (!IsPlayerAdmin(playernum)) - { - CONS_Alert(CONS_WARNING, M_GetText("Illegal request map queue command received from %s\n"), player_names[playernum]); - if (server && playernum != serverplayer) - SendKick(playernum, KICK_MSG_CON_FAIL); - return; - } - - doclear = (setgametype == ROUNDQUEUE_CLEAR); - - if (doclear == true) - { - if (roundqueue.size == 0) - { - CONS_Alert(CONS_ERROR, "queuemap: Queue is already empty!\n"); - return; - } - } - else if (roundqueue.size >= ROUNDQUEUE_MAX) - { - CONS_Alert(CONS_ERROR, "queuemap: Unable to add map beyond %u\n", roundqueue.size); - return; - } - - if (client) - return; - - Handle_MapQueueSend(mapnumber, setgametype, setencore); -} - static void Got_MapQueuecmd(const UINT8 **cp, INT32 playernum) { UINT8 flags, queueposition, i; diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 01c46e6e3..8c28b83f4 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -180,8 +180,8 @@ typedef enum XD_SCHEDULETASK, // 34 XD_SCHEDULECLEAR, // 35 XD_AUTOMATE, // 36 - XD_REQMAPQUEUE, // 37 - XD_MAPQUEUE, // 38 + // 37 is free + XD_MAPQUEUE = XD_AUTOMATE+2, // 38 XD_CALLZVOTE, // 39 XD_SETZVOTE, // 40 XD_TEAMCHANGE, // 41 diff --git a/src/typedef.h b/src/typedef.h index 44341bd6a..256eddb52 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -83,6 +83,7 @@ TYPEDEF (challengeall_pak); TYPEDEF (responseall_pak); TYPEDEF (resultsall_pak); TYPEDEF (say_pak); +TYPEDEF (reqmapqueue_pak); TYPEDEF (netinfo_pak); // d_event.h