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.
This commit is contained in:
toaster 2024-09-29 22:03:39 +01:00
parent 8bd50ddb65
commit 512ec6c2eb
5 changed files with 106 additions and 74 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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