From 27c6f8ae4600308248cdbc8a5edcc16ae142950e Mon Sep 17 00:00:00 2001 From: oy Date: Wed, 21 Nov 2018 19:56:46 +0100 Subject: [PATCH] increased the token size to 32bit and set a minimum datasize of 512bytes for token request to counter reflection attacks. #1681 --- src/engine/shared/network.cpp | 74 ++++++++++++++--------------- src/engine/shared/network.h | 44 +++++++++-------- src/engine/shared/network_conn.cpp | 2 +- src/engine/shared/network_token.cpp | 13 +++-- 4 files changed, 70 insertions(+), 63 deletions(-) diff --git a/src/engine/shared/network.cpp b/src/engine/shared/network.cpp index 95823099e..e8802267e 100644 --- a/src/engine/shared/network.cpp +++ b/src/engine/shared/network.cpp @@ -97,14 +97,15 @@ void CNetBase::SendPacketConnless(NETSOCKET Socket, const NETADDR *pAddr, TOKEN dbg_assert((ResponseToken&~NET_TOKEN_MASK) == 0, "resp token out of range"); int i = 0; - aBuffer[i++] = (Token>>12)&0xff; // token - aBuffer[i++] = (Token>>4)&0xff; - aBuffer[i++] = ((Token&0xf)<<4) - | (NET_PACKETFLAG_CONNLESS&0xf); // connless flag - aBuffer[i++] = ((NET_PACKETVERSION&0x0f)<<4) // version - | ((ResponseToken>>16)&0xf); // response token + aBuffer[i++] = (Token>>24)&0xff; // token + aBuffer[i++] = (Token>>16)&0xff; + aBuffer[i++] = (Token>>8)&0xff; + aBuffer[i++] = (Token)&0xff; + aBuffer[i++] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03); // connless flag and version + aBuffer[i++] = (ResponseToken>>24)&0xff; // response token + aBuffer[i++] = (ResponseToken>>16)&0xff; aBuffer[i++] = (ResponseToken>>8)&0xff; - aBuffer[i++] = ResponseToken&0xff; + aBuffer[i++] = (ResponseToken)&0xff; dbg_assert(i == NET_PACKETHEADERSIZE_CONNLESS, "inconsistency"); @@ -154,13 +155,13 @@ void CNetBase::SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketCons FinalSize += NET_PACKETHEADERSIZE; int i = 0; - aBuffer[i++] = (pPacket->m_Token>>12)&0xff; // token - aBuffer[i++] = (pPacket->m_Token>>4)&0xff; - aBuffer[i++] = ((pPacket->m_Token<<4)&0xf0) - | ((pPacket->m_Flags)&0xf); // flags - aBuffer[i++] = (pPacket->m_Ack>>2)&0xff; // ack - aBuffer[i++] = ((pPacket->m_Ack<<6)&0xc0) - | (pPacket->m_NumChunks&0x3f); + aBuffer[i++] = (pPacket->m_Token>>24)&0xff; // token + aBuffer[i++] = (pPacket->m_Token>>16)&0xff; + aBuffer[i++] = (pPacket->m_Token>>8)&0xff; + aBuffer[i++] = (pPacket->m_Token)&0xff; + aBuffer[i++] = ((pPacket->m_Flags<<2)&0xfc) | ((pPacket->m_Ack>>8)&0x03); // flags and ack + aBuffer[i++] = (pPacket->m_Ack)&0xff; // ack + aBuffer[i++] = (pPacket->m_NumChunks)&0xff; // num chunks dbg_assert(i == NET_PACKETHEADERSIZE, "inconsistency"); @@ -200,11 +201,10 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct } // read the packet - pPacket->m_Token = (pBuffer[0]<<12) | (pBuffer[1]<<4) | (pBuffer[2]>>4); - // TTTTTTTT TTTTTTTT TTTTxxxx - pPacket->m_Flags = pBuffer[2]&0x0f; - // xxxxFFFF - + pPacket->m_Token = (pBuffer[0]<<24) | (pBuffer[1]<<16) | (pBuffer[2]<<8) | pBuffer[3]; + // TTTTTTTT TTTTTTTT TTTTTTTT TTTTTTTT + pPacket->m_Flags = (pBuffer[4]&0xfc)>>2; + // FFFFFFxx if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS) { if(Size < NET_PACKETHEADERSIZE_CONNLESS) @@ -217,15 +217,15 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct pPacket->m_Flags = NET_PACKETFLAG_CONNLESS; pPacket->m_Ack = 0; pPacket->m_NumChunks = 0; - int Version = (pBuffer[3]>>4); - // VVVVxxxx + int Version = pBuffer[4]&0x3; + // xxxxxxVV if(Version != NET_PACKETVERSION) return -1; pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE_CONNLESS; - pPacket->m_ResponseToken = ((pBuffer[3]&0x0f)<<16) | (pBuffer[4]<<8) | pBuffer[5]; - // xxxxRRRR RRRRRRRR RRRRRRRR + pPacket->m_ResponseToken = (pBuffer[5]<<24) | (pBuffer[6]<<16) | (pBuffer[7]<<8) | pBuffer[8]; + // RRRRRRRR RRRRRRRR RRRRRRRR RRRRRRRR mem_copy(pPacket->m_aChunkData, &pBuffer[NET_PACKETHEADERSIZE_CONNLESS], pPacket->m_DataSize); } else @@ -237,10 +237,10 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct return -1; } - pPacket->m_Ack = (pBuffer[3]<<2) | ((pBuffer[4]&0xc0)>>6); - // AAAAAAAA AAxxxxxx - pPacket->m_NumChunks = pBuffer[4]&0x3f; - // xxNNNNNN + pPacket->m_Ack = ((pBuffer[4]&0x3)<<2) | pBuffer[5]; + // xxxxxxAA AAAAAAAA + pPacket->m_NumChunks = pBuffer[6]; + // NNNNNNNN pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE; pPacket->m_ResponseToken = NET_TOKEN_NONE; @@ -262,13 +262,13 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct // set the response token (a bit hacky because this function shouldn't know about control packets) if(pPacket->m_Flags&NET_PACKETFLAG_CONTROL) { - if(pPacket->m_DataSize >= 4) // control byte + token + if(pPacket->m_DataSize >= 5) // control byte + token { if(pPacket->m_aChunkData[0] == NET_CTRLMSG_CONNECT || pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN) { - pPacket->m_ResponseToken = ((pPacket->m_aChunkData[1]&0xf)<<16) - | (pPacket->m_aChunkData[2]<<8) | pPacket->m_aChunkData[3]; + pPacket->m_ResponseToken = (pPacket->m_aChunkData[1]<<24) | (pPacket->m_aChunkData[2]<<16) + | (pPacket->m_aChunkData[3]<<8) | pPacket->m_aChunkData[4]; } } } @@ -304,17 +304,17 @@ void CNetBase::SendControlMsg(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Toke } -void CNetBase::SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken) +void CNetBase::SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended) { dbg_assert((Token&~NET_TOKEN_MASK) == 0, "token out of range"); dbg_assert((MyToken&~NET_TOKEN_MASK) == 0, "resp token out of range"); - unsigned char aToken[3]; - aToken[0] = (MyToken>>16)&0xff; - aToken[1] = (MyToken>>8)&0xff; - aToken[2] = (MyToken)&0xff; - - SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aToken, sizeof(aToken)); + static unsigned char aBuf[NET_TOKENREQUEST_DATASIZE] = { 0 }; + aBuf[0] = (MyToken>>24)&0xff; + aBuf[1] = (MyToken>>16)&0xff; + aBuf[2] = (MyToken>>8)&0xff; + aBuf[3] = (MyToken)&0xff; + SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aBuf, Extended ? sizeof(aBuf) : 4); } unsigned char *CNetChunkHeader::Pack(unsigned char *pData) diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index cd9d094c2..bfae91d2b 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -9,32 +9,36 @@ /* CURRENT: - packet header: 5 bytes (6 bytes for connless) - unsigned char token[2]; // 16bit token - unsigned char token_flags; // 4bit token, 4bit flags - unsigned char ack; // 8bit ack - unsigned char ack_numchunks; // 2bit ack, 6bit chunks + packet header: 7 bytes (9 bytes for connless) + unsigned char token[4]; // 32bit token + unsigned char flags; // 6bit flags, 2bit ack + unsigned char ack; // 8bit ack + unsigned char numchunks; // 8bit chunks // TTTTTTTT // TTTTTTTT - // TTTTffff + // TTTTTTTT + // TTTTTTTT + // ffffffaa // aaaaaaaa - // aaNNNNNN + // NNNNNNNN packet header (CONNLESS): - unsigned char token[2]; // 16bit token - unsigned char token_flag; // 4bit token, 4bit flags - unsigned char version_responsetoken; // 4bit version, 4bit response token - unsigned char responsetoken[2]; // 16bit response token + unsigned char token[4]; // 32bit token + unsigned char flag_version; // 6bit flags, 2bits version + unsigned char responsetoken[4]; // 32bit response token // TTTTTTTT // TTTTTTTT - // TTTTffff - // vvvvRRRR + // TTTTTTTT + // TTTTTTTT + // ffffffvv + // RRRRRRRR + // RRRRRRRR // RRRRRRRR // RRRRRRRR if the token isn't explicitely set by any means, it must be set to - 0xfffff + 0xffffffff chunk header: 2-3 bytes unsigned char flags_size; // 2bit flags, 6 bit size @@ -62,13 +66,11 @@ enum enum { - NET_VERSION = 2, - NET_MAX_CHUNKHEADERSIZE = 3, // packets - NET_PACKETHEADERSIZE = 5, - NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 1, + NET_PACKETHEADERSIZE = 7, + NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 2, NET_MAX_PACKETHEADERSIZE = NET_PACKETHEADERSIZE_CONNLESS, NET_MAX_PACKETSIZE = 1400, @@ -88,13 +90,15 @@ enum NET_TOKENCACHE_ADDRESSEXPIRY = NET_SEEDTIME, NET_TOKENCACHE_PACKETEXPIRY = 5, - NET_TOKEN_MAX = 0xfffff, + NET_TOKEN_MAX = 0xffffffff, NET_TOKEN_NONE = NET_TOKEN_MAX, NET_TOKEN_MASK = NET_TOKEN_MAX, NET_TOKENFLAG_ALLOWBROADCAST = 1, NET_TOKENFLAG_RESPONSEONLY = 2, + NET_TOKENREQUEST_DATASIZE = 512, + // NET_MAX_CLIENTS = 16, NET_MAX_CONSOLE_CLIENTS = 4, @@ -536,7 +540,7 @@ public: static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize); static void SendControlMsg(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, const void *pExtra, int ExtraSize); - static void SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken); + static void SendControlMsgWithToken(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, int Ack, int ControlMsg, TOKEN MyToken, bool Extended); static void SendPacketConnless(NETSOCKET Socket, const NETADDR *pAddr, TOKEN Token, TOKEN ResponseToken, const void *pData, int DataSize); static void SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketConstruct *pPacket); static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket); diff --git a/src/engine/shared/network_conn.cpp b/src/engine/shared/network_conn.cpp index ada84e5b7..ec94dc5de 100644 --- a/src/engine/shared/network_conn.cpp +++ b/src/engine/shared/network_conn.cpp @@ -174,7 +174,7 @@ void CNetConnection::SendPacketConnless(const char *pData, int DataSize) void CNetConnection::SendControlWithToken(int ControlMsg) { m_LastSendTime = time_get(); - CNetBase::SendControlMsgWithToken(m_Socket, &m_PeerAddr, m_PeerToken, 0, ControlMsg, m_Token); + CNetBase::SendControlMsgWithToken(m_Socket, &m_PeerAddr, m_PeerToken, 0, ControlMsg, m_Token, true); } void CNetConnection::ResendChunk(CNetChunkResend *pResend) diff --git a/src/engine/shared/network_token.cpp b/src/engine/shared/network_token.cpp index 31b69aef8..9896d5d9e 100644 --- a/src/engine/shared/network_token.cpp +++ b/src/engine/shared/network_token.cpp @@ -63,9 +63,12 @@ int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConst return BroadcastResponse ? -1 : 1; // everything is fine, token exchange complete // client requesting token - CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr, - pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN, - GenerateToken(pAddr)); + if(pPacket->m_DataSize >= NET_TOKENREQUEST_DATASIZE) + { + CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr, + pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN, + GenerateToken(pAddr), false); + } return 0; // no need to process NET_CTRLMSG_TOKEN further } @@ -96,7 +99,7 @@ TOKEN CNetTokenManager::GenerateToken(const NETADDR *pAddr, int64 Seed) static const NETADDR NullAddr = { 0 }; NETADDR Addr; char aBuf[sizeof(NETADDR) + sizeof(int64)]; - int Result; + unsigned int Result; if(pAddr->type & NETTYPE_LINK_BROADCAST) return GenerateToken(&NullAddr, Seed); @@ -252,7 +255,7 @@ TOKEN CNetTokenCache::GetToken(const NETADDR *pAddr) void CNetTokenCache::FetchToken(const NETADDR *pAddr) { CNetBase::SendControlMsgWithToken(m_Socket, pAddr, NET_TOKEN_NONE, 0, - NET_CTRLMSG_TOKEN, m_pTokenManager->GenerateToken(pAddr)); + NET_CTRLMSG_TOKEN, m_pTokenManager->GenerateToken(pAddr), true); } void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token, int TokenFLag)