Added response token and CNetTokenManager

Conflicts:

	src/engine/shared/network_client.cpp
This commit is contained in:
heinrich5991 2012-03-25 18:03:49 +02:00 committed by oy
parent eaa036ed0f
commit 2ba3cf859f
5 changed files with 142 additions and 2 deletions

View file

@ -82,6 +82,7 @@ int CNetRecvUnpacker::FetchChunk(CNetChunk *pChunk)
pChunk->m_Flags = Header.m_Flags;
pChunk->m_DataSize = Header.m_Size;
pChunk->m_pData = pData;
pChunk->m_ResponseToken = NET_TOKEN_NONE;
return 1;
}
}

View file

@ -103,10 +103,11 @@ typedef int (*NETFUNC_NEWCLIENT)(int ClientID, void *pUser);
struct CNetChunk
{
// -1 means that it's a stateless packet
// -1 means that it's a connless packet
// 0 on the client means the server
int m_ClientID;
NETADDR m_Address; // only used when client_id == -1
NETADDR m_Address; // only used when cid == -1
unsigned int m_ResponseToken; // only used when cid == -1
int m_Flags;
int m_DataSize;
const void *m_pData;
@ -149,6 +150,28 @@ public:
};
class CNetTokenManager
{
public:
void Init(NETSOCKET Socket);
void GenerateSeed();
void ProcessTokenMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket);
bool CheckToken(const NETADDR *pAddr, unsigned int Token, unsigned int ResponseToken);
bool ConnectionToken(unsigned int Token);
static unsigned int GenerateToken(const NETADDR *pAddr, int64 Seed);
private:
NETSOCKET m_Socket;
int64 m_Seed;
int64 m_PrevSeed;
};
class CNetConnection
{
// TODO: is this needed because this needs to be aware of
@ -292,6 +315,8 @@ class CNetServer
CNetRecvUnpacker m_RecvUnpacker;
CNetTokenManager m_TokenManager;
public:
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
@ -335,6 +360,8 @@ class CNetConsole
CNetRecvUnpacker m_RecvUnpacker;
CNetTokenManager m_TokenManager;
public:
void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);

View file

@ -17,6 +17,9 @@ bool CNetClient::Open(NETADDR BindAddr, int Flags)
// init
m_Socket = Socket;
m_Connection.Init(m_Socket, false);
m_TokenManager.Init(Socket);
return true;
}

View file

@ -18,6 +18,8 @@ bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int Ma
if(!m_Socket.type)
return false;
m_TokenManager.Init(m_Socket);
m_pNetBan = pNetBan;
// clamp clients
@ -126,6 +128,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
pChunk->m_Address = Addr;
pChunk->m_DataSize = m_RecvUnpacker.m_Data.m_DataSize;
pChunk->m_pData = m_RecvUnpacker.m_Data.m_aChunkData;
pChunk->m_ResponseToken = m_RecvUnpacker.m_Data.m_ResponseToken;
return 1;
}
else

View file

@ -0,0 +1,106 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <stdlib.h> // rand
#include <base/system.h>
#include <engine/external/md5/md5.h>
#include "network.h"
static unsigned int Hash(char *pData, int Size)
{
md5_state_t State;
unsigned int Result;
md5_byte_t aDigest[sizeof(Result)];
md5_init(&State);
md5_append(&State, (const md5_byte_t *)pData, Size);
md5_finish(&State, aDigest);
mem_copy(&Result, aDigest, sizeof(Result));
return Result;
}
void CNetTokenManager::Init(NETSOCKET Socket)
{
m_Socket = Socket;
GenerateSeed();
}
int CNetTokenManager::ProcessMessage(const NETADDR *pAddr, const CNetPacketConstruct *pPacket)
{
if(pPacket->m_Token != NET_TOKEN_NONE && !CheckToken(pAddr, pPacket->m_Token))
return 0; // wrong token, silent ignore
bool Verified = pPacket->m_Token != NET_TOKEN_NONE;
bool TokenMessage = (pPacket->m_Flags & NET_PACKETFLAG_CONTROL)
&& pPacket->m_aChunkData[0] == NET_CTRLMSG_TOKEN;
if(pPacket->m_Flags&NETSENDFLAG_CONNLESS)
return (Verified) ? 1 : -1; // connless packets without token are allowed
if(!TokenMessage)
if(Verified)
return 1; // verified packet
else
// the only allowed not connless packet
// without token is NET_CTRLMSG_TOKEN
return 0;
if(Verified && TokenMessage)
return 0; // everything is fine, token exchange complete
// client requesting token
unsigned int RemoteToken = (pPacket->m_aChunkData[0]<<24)
| (pPacket->m_aChunkData[1]<<16)
| (pPacket->m_aChunkData[2]<<8)
| (pPacket->m_aChunkData[3]);
CNetBase::SendToken(m_Socket, (NETADDR *)pAddr, GenerateToken(pAddr, m_Seed), RemoteToken);
return 0; // no need to process NET_CTRLMSG_TOKEN further
}
void CNetTokenManager::GenerateSeed()
{
m_PrevSeed = m_Seed;
for(int i = 0; i < 4; i++)
{
// rand() returns a random integer between 0 and RAND_MAX
// RAND_MAX is at least 1<<16 according to the standard
m_Seed <<= 16;
m_Seed ^= rand();
}
}
unsigned int CNetTokenManager::GenerateToken(const NETADDR *pAddr, int64 Seed)
{
char aBuf[sizeof(NETADDR) + sizeof(int64)];
int Result;
mem_copy(aBuf, pAddr, sizeof(NETADDR));
mem_copy(aBuf + sizeof(NETADDR), &Seed, sizeof(int64));
Result = Hash(aBuf, sizeof(aBuf));
if(Result == NET_TOKEN_NONE)
Result++;
return Result;
}
bool CNetTokenManager::CheckToken(const NETADDR *pAddr, unsigned int Token, unsigned int ResponseToken)
{
unsigned int CurrentToken = GenerateToken(pAddr, m_Seed);
if(CurrentToken == Token)
return true;
if(GenerateToken(pAddr, m_PrevSeed) == Token)
{
CNetBase::SendToken(m_Socket, (NETADDR *)pAddr, CurrentToken, ResponseToken); // notify the peer about the new token
return true;
}
return false;
}