increased the token size to 32bit and set a minimum datasize of 512bytes for token request to counter reflection attacks. #1681

This commit is contained in:
oy 2018-11-21 19:56:46 +01:00
parent 646d055a59
commit 27c6f8ae46
4 changed files with 70 additions and 63 deletions

View file

@ -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"); dbg_assert((ResponseToken&~NET_TOKEN_MASK) == 0, "resp token out of range");
int i = 0; int i = 0;
aBuffer[i++] = (Token>>12)&0xff; // token aBuffer[i++] = (Token>>24)&0xff; // token
aBuffer[i++] = (Token>>4)&0xff; aBuffer[i++] = (Token>>16)&0xff;
aBuffer[i++] = ((Token&0xf)<<4) aBuffer[i++] = (Token>>8)&0xff;
| (NET_PACKETFLAG_CONNLESS&0xf); // connless flag aBuffer[i++] = (Token)&0xff;
aBuffer[i++] = ((NET_PACKETVERSION&0x0f)<<4) // version aBuffer[i++] = ((NET_PACKETFLAG_CONNLESS<<2)&0xfc) | (NET_PACKETVERSION&0x03); // connless flag and version
| ((ResponseToken>>16)&0xf); // response token aBuffer[i++] = (ResponseToken>>24)&0xff; // response token
aBuffer[i++] = (ResponseToken>>16)&0xff;
aBuffer[i++] = (ResponseToken>>8)&0xff; aBuffer[i++] = (ResponseToken>>8)&0xff;
aBuffer[i++] = ResponseToken&0xff; aBuffer[i++] = (ResponseToken)&0xff;
dbg_assert(i == NET_PACKETHEADERSIZE_CONNLESS, "inconsistency"); dbg_assert(i == NET_PACKETHEADERSIZE_CONNLESS, "inconsistency");
@ -154,13 +155,13 @@ void CNetBase::SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketCons
FinalSize += NET_PACKETHEADERSIZE; FinalSize += NET_PACKETHEADERSIZE;
int i = 0; int i = 0;
aBuffer[i++] = (pPacket->m_Token>>12)&0xff; // token aBuffer[i++] = (pPacket->m_Token>>24)&0xff; // token
aBuffer[i++] = (pPacket->m_Token>>4)&0xff; aBuffer[i++] = (pPacket->m_Token>>16)&0xff;
aBuffer[i++] = ((pPacket->m_Token<<4)&0xf0) aBuffer[i++] = (pPacket->m_Token>>8)&0xff;
| ((pPacket->m_Flags)&0xf); // flags aBuffer[i++] = (pPacket->m_Token)&0xff;
aBuffer[i++] = (pPacket->m_Ack>>2)&0xff; // ack aBuffer[i++] = ((pPacket->m_Flags<<2)&0xfc) | ((pPacket->m_Ack>>8)&0x03); // flags and ack
aBuffer[i++] = ((pPacket->m_Ack<<6)&0xc0) aBuffer[i++] = (pPacket->m_Ack)&0xff; // ack
| (pPacket->m_NumChunks&0x3f); aBuffer[i++] = (pPacket->m_NumChunks)&0xff; // num chunks
dbg_assert(i == NET_PACKETHEADERSIZE, "inconsistency"); dbg_assert(i == NET_PACKETHEADERSIZE, "inconsistency");
@ -200,11 +201,10 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
} }
// read the packet // read the packet
pPacket->m_Token = (pBuffer[0]<<12) | (pBuffer[1]<<4) | (pBuffer[2]>>4); pPacket->m_Token = (pBuffer[0]<<24) | (pBuffer[1]<<16) | (pBuffer[2]<<8) | pBuffer[3];
// TTTTTTTT TTTTTTTT TTTTxxxx // TTTTTTTT TTTTTTTT TTTTTTTT TTTTTTTT
pPacket->m_Flags = pBuffer[2]&0x0f; pPacket->m_Flags = (pBuffer[4]&0xfc)>>2;
// xxxxFFFF // FFFFFFxx
if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS) if(pPacket->m_Flags&NET_PACKETFLAG_CONNLESS)
{ {
if(Size < NET_PACKETHEADERSIZE_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_Flags = NET_PACKETFLAG_CONNLESS;
pPacket->m_Ack = 0; pPacket->m_Ack = 0;
pPacket->m_NumChunks = 0; pPacket->m_NumChunks = 0;
int Version = (pBuffer[3]>>4); int Version = pBuffer[4]&0x3;
// VVVVxxxx // xxxxxxVV
if(Version != NET_PACKETVERSION) if(Version != NET_PACKETVERSION)
return -1; return -1;
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE_CONNLESS; pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE_CONNLESS;
pPacket->m_ResponseToken = ((pBuffer[3]&0x0f)<<16) | (pBuffer[4]<<8) | pBuffer[5]; pPacket->m_ResponseToken = (pBuffer[5]<<24) | (pBuffer[6]<<16) | (pBuffer[7]<<8) | pBuffer[8];
// xxxxRRRR RRRRRRRR RRRRRRRR // RRRRRRRR RRRRRRRR RRRRRRRR RRRRRRRR
mem_copy(pPacket->m_aChunkData, &pBuffer[NET_PACKETHEADERSIZE_CONNLESS], pPacket->m_DataSize); mem_copy(pPacket->m_aChunkData, &pBuffer[NET_PACKETHEADERSIZE_CONNLESS], pPacket->m_DataSize);
} }
else else
@ -237,10 +237,10 @@ int CNetBase::UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct
return -1; return -1;
} }
pPacket->m_Ack = (pBuffer[3]<<2) | ((pBuffer[4]&0xc0)>>6); pPacket->m_Ack = ((pBuffer[4]&0x3)<<2) | pBuffer[5];
// AAAAAAAA AAxxxxxx // xxxxxxAA AAAAAAAA
pPacket->m_NumChunks = pBuffer[4]&0x3f; pPacket->m_NumChunks = pBuffer[6];
// xxNNNNNN // NNNNNNNN
pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE; pPacket->m_DataSize = Size - NET_PACKETHEADERSIZE;
pPacket->m_ResponseToken = NET_TOKEN_NONE; 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) // 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_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 if(pPacket->m_aChunkData[0] == NET_CTRLMSG_CONNECT
|| pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN) || pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN)
{ {
pPacket->m_ResponseToken = ((pPacket->m_aChunkData[1]&0xf)<<16) pPacket->m_ResponseToken = (pPacket->m_aChunkData[1]<<24) | (pPacket->m_aChunkData[2]<<16)
| (pPacket->m_aChunkData[2]<<8) | pPacket->m_aChunkData[3]; | (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((Token&~NET_TOKEN_MASK) == 0, "token out of range");
dbg_assert((MyToken&~NET_TOKEN_MASK) == 0, "resp token out of range"); dbg_assert((MyToken&~NET_TOKEN_MASK) == 0, "resp token out of range");
unsigned char aToken[3]; static unsigned char aBuf[NET_TOKENREQUEST_DATASIZE] = { 0 };
aToken[0] = (MyToken>>16)&0xff; aBuf[0] = (MyToken>>24)&0xff;
aToken[1] = (MyToken>>8)&0xff; aBuf[1] = (MyToken>>16)&0xff;
aToken[2] = (MyToken)&0xff; aBuf[2] = (MyToken>>8)&0xff;
aBuf[3] = (MyToken)&0xff;
SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aToken, sizeof(aToken)); SendControlMsg(Socket, pAddr, Token, 0, ControlMsg, aBuf, Extended ? sizeof(aBuf) : 4);
} }
unsigned char *CNetChunkHeader::Pack(unsigned char *pData) unsigned char *CNetChunkHeader::Pack(unsigned char *pData)

View file

@ -9,32 +9,36 @@
/* /*
CURRENT: CURRENT:
packet header: 5 bytes (6 bytes for connless) packet header: 7 bytes (9 bytes for connless)
unsigned char token[2]; // 16bit token unsigned char token[4]; // 32bit token
unsigned char token_flags; // 4bit token, 4bit flags unsigned char flags; // 6bit flags, 2bit ack
unsigned char ack; // 8bit ack unsigned char ack; // 8bit ack
unsigned char ack_numchunks; // 2bit ack, 6bit chunks unsigned char numchunks; // 8bit chunks
// TTTTTTTT // TTTTTTTT
// TTTTTTTT // TTTTTTTT
// TTTTffff // TTTTTTTT
// TTTTTTTT
// ffffffaa
// aaaaaaaa // aaaaaaaa
// aaNNNNNN // NNNNNNNN
packet header (CONNLESS): packet header (CONNLESS):
unsigned char token[2]; // 16bit token unsigned char token[4]; // 32bit token
unsigned char token_flag; // 4bit token, 4bit flags unsigned char flag_version; // 6bit flags, 2bits version
unsigned char version_responsetoken; // 4bit version, 4bit response token unsigned char responsetoken[4]; // 32bit response token
unsigned char responsetoken[2]; // 16bit response token
// TTTTTTTT // TTTTTTTT
// TTTTTTTT // TTTTTTTT
// TTTTffff // TTTTTTTT
// vvvvRRRR // TTTTTTTT
// ffffffvv
// RRRRRRRR
// RRRRRRRR
// RRRRRRRR // RRRRRRRR
// RRRRRRRR // RRRRRRRR
if the token isn't explicitely set by any means, it must be set to if the token isn't explicitely set by any means, it must be set to
0xfffff 0xffffffff
chunk header: 2-3 bytes chunk header: 2-3 bytes
unsigned char flags_size; // 2bit flags, 6 bit size unsigned char flags_size; // 2bit flags, 6 bit size
@ -62,13 +66,11 @@ enum
enum enum
{ {
NET_VERSION = 2,
NET_MAX_CHUNKHEADERSIZE = 3, NET_MAX_CHUNKHEADERSIZE = 3,
// packets // packets
NET_PACKETHEADERSIZE = 5, NET_PACKETHEADERSIZE = 7,
NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 1, NET_PACKETHEADERSIZE_CONNLESS = NET_PACKETHEADERSIZE + 2,
NET_MAX_PACKETHEADERSIZE = NET_PACKETHEADERSIZE_CONNLESS, NET_MAX_PACKETHEADERSIZE = NET_PACKETHEADERSIZE_CONNLESS,
NET_MAX_PACKETSIZE = 1400, NET_MAX_PACKETSIZE = 1400,
@ -88,13 +90,15 @@ enum
NET_TOKENCACHE_ADDRESSEXPIRY = NET_SEEDTIME, NET_TOKENCACHE_ADDRESSEXPIRY = NET_SEEDTIME,
NET_TOKENCACHE_PACKETEXPIRY = 5, NET_TOKENCACHE_PACKETEXPIRY = 5,
NET_TOKEN_MAX = 0xfffff, NET_TOKEN_MAX = 0xffffffff,
NET_TOKEN_NONE = NET_TOKEN_MAX, NET_TOKEN_NONE = NET_TOKEN_MAX,
NET_TOKEN_MASK = NET_TOKEN_MAX, NET_TOKEN_MASK = NET_TOKEN_MAX,
NET_TOKENFLAG_ALLOWBROADCAST = 1, NET_TOKENFLAG_ALLOWBROADCAST = 1,
NET_TOKENFLAG_RESPONSEONLY = 2, NET_TOKENFLAG_RESPONSEONLY = 2,
NET_TOKENREQUEST_DATASIZE = 512,
// //
NET_MAX_CLIENTS = 16, NET_MAX_CLIENTS = 16,
NET_MAX_CONSOLE_CLIENTS = 4, NET_MAX_CONSOLE_CLIENTS = 4,
@ -536,7 +540,7 @@ public:
static int Decompress(const void *pData, int DataSize, void *pOutput, int OutputSize); 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 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 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 void SendPacket(NETSOCKET Socket, const NETADDR *pAddr, CNetPacketConstruct *pPacket);
static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket); static int UnpackPacket(unsigned char *pBuffer, int Size, CNetPacketConstruct *pPacket);

View file

@ -174,7 +174,7 @@ void CNetConnection::SendPacketConnless(const char *pData, int DataSize)
void CNetConnection::SendControlWithToken(int ControlMsg) void CNetConnection::SendControlWithToken(int ControlMsg)
{ {
m_LastSendTime = time_get(); 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) void CNetConnection::ResendChunk(CNetChunkResend *pResend)

View file

@ -63,9 +63,12 @@ int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConst
return BroadcastResponse ? -1 : 1; // everything is fine, token exchange complete return BroadcastResponse ? -1 : 1; // everything is fine, token exchange complete
// client requesting token // client requesting token
if(pPacket->m_DataSize >= NET_TOKENREQUEST_DATASIZE)
{
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr, CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN, pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN,
GenerateToken(pAddr)); GenerateToken(pAddr), false);
}
return 0; // no need to process NET_CTRLMSG_TOKEN further 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 }; static const NETADDR NullAddr = { 0 };
NETADDR Addr; NETADDR Addr;
char aBuf[sizeof(NETADDR) + sizeof(int64)]; char aBuf[sizeof(NETADDR) + sizeof(int64)];
int Result; unsigned int Result;
if(pAddr->type & NETTYPE_LINK_BROADCAST) if(pAddr->type & NETTYPE_LINK_BROADCAST)
return GenerateToken(&NullAddr, Seed); return GenerateToken(&NullAddr, Seed);
@ -252,7 +255,7 @@ TOKEN CNetTokenCache::GetToken(const NETADDR *pAddr)
void CNetTokenCache::FetchToken(const NETADDR *pAddr) void CNetTokenCache::FetchToken(const NETADDR *pAddr)
{ {
CNetBase::SendControlMsgWithToken(m_Socket, pAddr, NET_TOKEN_NONE, 0, 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) void CNetTokenCache::AddToken(const NETADDR *pAddr, TOKEN Token, int TokenFLag)