Added CRC to packets
Verify that data is correctly ordered and reject packets that aren't. Also generates a random game id to ensure packets are coming from legitimate clients.
This commit is contained in:
parent
9e2b1f9c4c
commit
7877018471
3 changed files with 67 additions and 32 deletions
|
|
@ -78,6 +78,7 @@
|
|||
#include "c_cvars.h"
|
||||
#include "version.h"
|
||||
#include "i_net.h"
|
||||
#include "m_random.h"
|
||||
|
||||
/* [Petteri] Get more portable: */
|
||||
#ifndef __WIN32__
|
||||
|
|
@ -162,13 +163,14 @@ int consoleplayer = 0;
|
|||
int Net_Arbitrator = 0;
|
||||
FClientStack NetworkClients = {};
|
||||
|
||||
uint32_t GameID = DEFAULT_GAME_ID;
|
||||
uint64_t GameID = 0u;
|
||||
uint8_t TicDup = 1u;
|
||||
int MaxClients = 1;
|
||||
int RemoteClient = -1;
|
||||
size_t NetBufferLength = 0u;
|
||||
uint8_t NetBuffer[MAX_MSGLEN] = {};
|
||||
|
||||
static FRandom GameIDGen = {};
|
||||
static u_short GamePort = (IPPORT_USERRESERVED + 29);
|
||||
static SOCKET MySocket = INVALID_SOCKET;
|
||||
static FConnection Connected[MAXPLAYERS] = {};
|
||||
|
|
@ -483,22 +485,34 @@ static void SendPacket(const sockaddr_in& to)
|
|||
|
||||
assert(!(NetBuffer[0] & NCMD_COMPRESSED));
|
||||
|
||||
uLong size = MaxTransmitSize - 1u;
|
||||
int res = -1;
|
||||
uint8_t* dataStart = &TransmitBuffer[4];
|
||||
uLong size = MaxTransmitSize - 5u;
|
||||
if (NetBufferLength >= MinCompressionSize)
|
||||
{
|
||||
TransmitBuffer[0] = NetBuffer[0] | NCMD_COMPRESSED;
|
||||
*dataStart = NetBuffer[0] | NCMD_COMPRESSED;
|
||||
const int res = compress2(dataStart + 1, &size, NetBuffer + 1, NetBufferLength - 1u, 9);
|
||||
if (res != Z_OK)
|
||||
I_Error("Net compression failed (zlib error %d)", res);
|
||||
|
||||
res = compress2(TransmitBuffer + 1, &size, NetBuffer + 1, uint32_t(NetBufferLength - 1u), 9);
|
||||
++size;
|
||||
}
|
||||
|
||||
if (res == Z_OK && size < static_cast<uLong>(NetBufferLength))
|
||||
res = sendto(MySocket, (const char*)TransmitBuffer, (int)size, 0, (const sockaddr*)&to, sizeof(to));
|
||||
else if (NetBufferLength > MaxTransmitSize)
|
||||
I_Error("Net compression failed (zlib error %d)", res);
|
||||
else
|
||||
res = sendto(MySocket, (const char*)NetBuffer, (int)NetBufferLength, 0, (const sockaddr*)&to, sizeof(to));
|
||||
{
|
||||
memcpy(dataStart, NetBuffer, NetBufferLength);
|
||||
size = NetBufferLength;
|
||||
}
|
||||
|
||||
if (size + 4 > MaxTransmitSize)
|
||||
I_Error("Failed to compress data down to acceptable transmission size");
|
||||
|
||||
// If a connection packet, don't check the game id since they might not have it yet.
|
||||
const uint32_t crc = (NetBuffer[0] & NCMD_SETUP) ? CalcCRC32(dataStart, size) : AddCRC32(CalcCRC32(dataStart, size), (uint8_t*)&GameID, sizeof(GameID));
|
||||
TransmitBuffer[0] = crc >> 24;
|
||||
TransmitBuffer[1] = crc >> 16;
|
||||
TransmitBuffer[2] = crc >> 8;
|
||||
TransmitBuffer[3] = crc;
|
||||
|
||||
sendto(MySocket, (const char*)TransmitBuffer, size + 4, 0, (const sockaddr*)&to, sizeof(to));
|
||||
}
|
||||
|
||||
static void GetPacket(sockaddr_in* const from = nullptr)
|
||||
|
|
@ -544,7 +558,8 @@ static void GetPacket(sockaddr_in* const from = nullptr)
|
|||
}
|
||||
else if (msgSize > 0)
|
||||
{
|
||||
if (client == -1 && !(TransmitBuffer[0] & NCMD_SETUP))
|
||||
const uint8_t* dataStart = &TransmitBuffer[4];
|
||||
if (client == -1 && !(*dataStart & NCMD_SETUP))
|
||||
{
|
||||
msgSize = 0;
|
||||
}
|
||||
|
|
@ -558,25 +573,37 @@ static void GetPacket(sockaddr_in* const from = nullptr)
|
|||
}
|
||||
else
|
||||
{
|
||||
NetBuffer[0] = (TransmitBuffer[0] & ~NCMD_COMPRESSED);
|
||||
if (TransmitBuffer[0] & NCMD_COMPRESSED)
|
||||
const uint32_t check = (*dataStart & NCMD_SETUP) ? CalcCRC32(dataStart, msgSize - 4) : AddCRC32(CalcCRC32(dataStart, msgSize - 4), (uint8_t*)GameID, sizeof(GameID));
|
||||
const uint32_t crc = (TransmitBuffer[0] << 24) | (TransmitBuffer[1] << 16) | (TransmitBuffer[2] << 8) | TransmitBuffer[3];
|
||||
if (check != crc)
|
||||
{
|
||||
uLongf size = MAX_MSGLEN - 1;
|
||||
int err = uncompress(NetBuffer + 1, &size, TransmitBuffer + 1, msgSize - 1);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars());
|
||||
client = -1;
|
||||
msgSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgSize = size + 1;
|
||||
}
|
||||
DPrintf(DMSG_NOTIFY, "Checksum on packet failed: expected %u, got %u", check, crc);
|
||||
client = -1;
|
||||
msgSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(NetBuffer + 1, TransmitBuffer + 1, msgSize - 1);
|
||||
NetBuffer[0] = (*dataStart & ~NCMD_COMPRESSED);
|
||||
if (*dataStart & NCMD_COMPRESSED)
|
||||
{
|
||||
uLongf size = MAX_MSGLEN - 1;
|
||||
int err = uncompress(NetBuffer + 1, &size, dataStart + 1, msgSize - 5);
|
||||
if (err != Z_OK)
|
||||
{
|
||||
Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars());
|
||||
client = -1;
|
||||
msgSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
msgSize = size + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msgSize -= 4;
|
||||
memcpy(NetBuffer + 1, dataStart + 1, msgSize - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -847,7 +874,15 @@ static bool Host_CheckForConnections(void* connected)
|
|||
{
|
||||
NetBuffer[1] = PRE_GAME_INFO;
|
||||
NetBuffer[2] = TicDup;
|
||||
NetBufferLength = 3u;
|
||||
NetBuffer[3] = GameID >> 56;
|
||||
NetBuffer[4] = GameID >> 48;
|
||||
NetBuffer[5] = GameID >> 40;
|
||||
NetBuffer[6] = GameID >> 32;
|
||||
NetBuffer[7] = GameID >> 24;
|
||||
NetBuffer[8] = GameID >> 16;
|
||||
NetBuffer[9] = GameID >> 8;
|
||||
NetBuffer[10] = GameID;
|
||||
NetBufferLength = 11u;
|
||||
|
||||
uint8_t* stream = &NetBuffer[NetBufferLength];
|
||||
NetBufferLength += Net_SetGameInfo(stream);
|
||||
|
|
@ -931,6 +966,7 @@ static bool HostGame(int arg, bool forcedNetMode)
|
|||
if (MaxClients > MAXPLAYERS)
|
||||
I_FatalError("Cannot host a game with %u players. The limit is currently %u", MaxClients, MAXPLAYERS);
|
||||
|
||||
GameID = GameIDGen.GenRand64();
|
||||
NetworkClients += 0;
|
||||
Connected[consoleplayer].Status = CSTAT_READY;
|
||||
Net_SetupUserInfo();
|
||||
|
|
@ -1092,7 +1128,9 @@ static bool Guest_ContactHost(void* unused)
|
|||
if (!Connected[consoleplayer].bHasGameInfo)
|
||||
{
|
||||
TicDup = clamp<int>(NetBuffer[2], 1, MAXTICDUP);
|
||||
uint8_t* stream = &NetBuffer[3];
|
||||
GameID = ((uint64_t)NetBuffer[3] << 56) | ((uint64_t)NetBuffer[4] << 48) | ((uint64_t)NetBuffer[5] << 40) | ((uint64_t)NetBuffer[6] << 32)
|
||||
| ((uint64_t)NetBuffer[7] << 24) | ((uint64_t)NetBuffer[8] << 16) | ((uint64_t)NetBuffer[9] << 8) | (uint64_t)NetBuffer[10];
|
||||
uint8_t* stream = &NetBuffer[11];
|
||||
Net_ReadGameInfo(stream);
|
||||
Connected[consoleplayer].bHasGameInfo = true;
|
||||
}
|
||||
|
|
@ -1255,6 +1293,7 @@ bool I_InitNetwork()
|
|||
else
|
||||
{
|
||||
// single player game
|
||||
GameID = GameIDGen.GenRand64();
|
||||
TicDup = 1;
|
||||
NetworkClients += 0;
|
||||
Connected[0].Status = CSTAT_READY;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ inline constexpr size_t MAXPLAYERS = 64u;
|
|||
|
||||
enum ENetConstants
|
||||
{
|
||||
DEFAULT_GAME_ID = 0x12345678,
|
||||
BACKUPTICS = 35 * 5, // Remember up to 5 seconds of data.
|
||||
MAXTICDUP = 3,
|
||||
MAXSENDTICS = 35 * 1, // Only send up to 1 second of data at a time.
|
||||
|
|
@ -67,7 +66,7 @@ extern size_t NetBufferLength;
|
|||
extern uint8_t TicDup;
|
||||
extern int RemoteClient;
|
||||
extern int MaxClients;
|
||||
extern uint32_t GameID;
|
||||
extern uint64_t GameID;
|
||||
|
||||
bool I_InitNetwork();
|
||||
void I_ClearClient(size_t client);
|
||||
|
|
|
|||
|
|
@ -1695,9 +1695,6 @@ bool D_CheckNetGame()
|
|||
if (!I_InitNetwork())
|
||||
return false;
|
||||
|
||||
if (GameID != DEFAULT_GAME_ID)
|
||||
I_FatalError("Invalid id set for network buffer");
|
||||
|
||||
if (Args->CheckParm("-extratic"))
|
||||
net_extratic = true;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue