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");
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)

View file

@ -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
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 ack_numchunks; // 2bit ack, 6bit chunks
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);

View file

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

View file

@ -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
if(pPacket->m_DataSize >= NET_TOKENREQUEST_DATASIZE)
{
CNetBase::SendControlMsgWithToken(m_Socket, (NETADDR *)pAddr,
pPacket->m_ResponseToken, 0, NET_CTRLMSG_TOKEN,
GenerateToken(pAddr));
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)