Implementing some brute force attack and denial of service countermeasure.

This commit is contained in:
lotodore
2009-12-23 09:53:01 +00:00
parent c68e59dad7
commit b0f764d4bd
8 changed files with 57 additions and 54 deletions
+2 -2
View File
@@ -631,8 +631,8 @@ ErrorMessage ::= [APPLICATION 255] SEQUENCE {
errorInitPlayerNameInUse (4), errorInitPlayerNameInUse (4),
errorInitInvalidPlayerName (5), errorInitInvalidPlayerName (5),
errorInitServerMaintenance (6), errorInitServerMaintenance (6),
errorAvatarTooLarge (7), errorInitBlocked (7),
errorAvatarUploadBlocked (8), errorAvatarTooLarge (8),
errorInvalidPacket (256), errorInvalidPacket (256),
errorInvalidState (257), errorInvalidState (257),
errorKickedFromServer (258), errorKickedFromServer (258),
+2 -2
View File
@@ -779,9 +779,9 @@ void startWindowImpl::networkError(int errorID, int /*osErrorID*/) {
tr("The selected avatar file is too large. Please choose a different avatar."), tr("The selected avatar file is too large. Please choose a different avatar."),
QMessageBox::Close); } QMessageBox::Close); }
break; break;
case ERR_NET_AVATAR_UPLOAD_BLOCKED: case ERR_NET_INIT_BLOCKED:
{ QMessageBox::warning(this, tr("Network Error"), { QMessageBox::warning(this, tr("Network Error"),
tr("You cannot upload a new avatar file at this time. Please try again in a few seconds."), tr("You cannot login at this time. Please try again in a few seconds."),
QMessageBox::Close); } QMessageBox::Close); }
break; break;
case ERR_NET_INVALID_REQUEST_ID: case ERR_NET_INVALID_REQUEST_ID:
+6 -6
View File
@@ -202,12 +202,12 @@ NetPacket::NetErrorToGameError(long netErrorReason)
case errorReason_errorInitServerMaintenance : case errorReason_errorInitServerMaintenance :
retVal = ERR_NET_SERVER_MAINTENANCE; retVal = ERR_NET_SERVER_MAINTENANCE;
break; break;
case errorReason_errorInitBlocked :
retVal = ERR_NET_INIT_BLOCKED;
break;
case errorReason_errorAvatarTooLarge : case errorReason_errorAvatarTooLarge :
retVal = ERR_NET_AVATAR_TOO_LARGE; retVal = ERR_NET_AVATAR_TOO_LARGE;
break; break;
case errorReason_errorAvatarUploadBlocked :
retVal = ERR_NET_AVATAR_UPLOAD_BLOCKED;
break;
case errorReason_errorInvalidPacket : case errorReason_errorInvalidPacket :
retVal = ERR_SOCK_INVALID_PACKET; retVal = ERR_SOCK_INVALID_PACKET;
break; break;
@@ -254,12 +254,12 @@ NetPacket::GameErrorToNetError(int gameErrorReason)
case ERR_NET_SERVER_MAINTENANCE : case ERR_NET_SERVER_MAINTENANCE :
retVal = errorReason_errorInitServerMaintenance; retVal = errorReason_errorInitServerMaintenance;
break; break;
case ERR_NET_INIT_BLOCKED :
retVal = errorReason_errorInitBlocked;
break;
case ERR_NET_AVATAR_TOO_LARGE : case ERR_NET_AVATAR_TOO_LARGE :
retVal = errorReason_errorAvatarTooLarge; retVal = errorReason_errorAvatarTooLarge;
break; break;
case ERR_NET_AVATAR_UPLOAD_BLOCKED :
retVal = errorReason_errorAvatarUploadBlocked;
break;
case ERR_SOCK_INVALID_PACKET : case ERR_SOCK_INVALID_PACKET :
retVal = errorReason_errorInvalidPacket; retVal = errorReason_errorInvalidPacket;
break; break;
+36 -33
View File
@@ -54,10 +54,10 @@
#define SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC 500 #define SERVER_CHECK_SESSION_TIMEOUTS_INTERVAL_MSEC 500
#define SERVER_REMOVE_GAME_INTERVAL_MSEC 500 #define SERVER_REMOVE_GAME_INTERVAL_MSEC 500
#define SERVER_REMOVE_PLAYER_INTERVAL_MSEC 100 #define SERVER_REMOVE_PLAYER_INTERVAL_MSEC 100
#define SERVER_UPDATE_AVATAR_LOCK_INTERVAL_MSEC 1000 #define SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC 1000
#define SERVER_PROCESS_SEND_INTERVAL_MSEC 10 #define SERVER_PROCESS_SEND_INTERVAL_MSEC 10
#define SERVER_INIT_AVATAR_CLIENT_LOCK_SEC 30 // Forbid a client to send an additional avatar. #define SERVER_INIT_LOGIN_CLIENT_LOCK_SEC 30 // Forbid a client to send an additional avatar.
#define SERVER_INIT_SESSION_TIMEOUT_SEC 60 #define SERVER_INIT_SESSION_TIMEOUT_SEC 60
#define SERVER_TIMEOUT_WARNING_REMAINING_SEC 60 #define SERVER_TIMEOUT_WARNING_REMAINING_SEC 60
@@ -145,7 +145,7 @@ ServerLobbyThread::ServerLobbyThread(GuiInterface &gui, ServerMode mode, ServerI
m_mode(mode), m_playerConfig(playerConfig), m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1), m_mode(mode), m_playerConfig(playerConfig), m_curGameId(0), m_curUniquePlayerId(0), m_curSessionId(INVALID_SESSION + 1),
m_statDataChanged(false), m_removeGameTimer(*ioService), m_removePlayerTimer(*ioService), m_statDataChanged(false), m_removeGameTimer(*ioService), m_removePlayerTimer(*ioService),
m_sessionTimeoutTimer(*ioService), m_avatarCleanupTimer(*ioService), m_sessionTimeoutTimer(*ioService), m_avatarCleanupTimer(*ioService),
m_saveStatisticsTimer(*ioService), m_avatarLockTimer(*ioService), m_saveStatisticsTimer(*ioService), m_loginLockTimer(*ioService),
m_startTime(boost::posix_time::second_clock::local_time()) m_startTime(boost::posix_time::second_clock::local_time())
{ {
m_internalServerCallback.reset(new InternalServerCallback(*this)); m_internalServerCallback.reset(new InternalServerCallback(*this));
@@ -698,11 +698,11 @@ ServerLobbyThread::RegisterTimers()
boost::bind( boost::bind(
&ServerLobbyThread::TimerSaveStatisticsFile, shared_from_this(), boost::asio::placeholders::error)); &ServerLobbyThread::TimerSaveStatisticsFile, shared_from_this(), boost::asio::placeholders::error));
// Update the avatar upload locks. // Update the avatar upload locks.
m_avatarLockTimer.expires_from_now( m_loginLockTimer.expires_from_now(
boost::posix_time::milliseconds(SERVER_UPDATE_AVATAR_LOCK_INTERVAL_MSEC)); boost::posix_time::milliseconds(SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC));
m_avatarLockTimer.async_wait( m_loginLockTimer.async_wait(
boost::bind( boost::bind(
&ServerLobbyThread::TimerUpdateClientAvatarLock, shared_from_this(), boost::asio::placeholders::error)); &ServerLobbyThread::TimerUpdateClientLoginLock, shared_from_this(), boost::asio::placeholders::error));
} }
void void
@@ -713,7 +713,7 @@ ServerLobbyThread::CancelTimers()
m_sessionTimeoutTimer.cancel(); m_sessionTimeoutTimer.cancel();
m_avatarCleanupTimer.cancel(); m_avatarCleanupTimer.cancel();
m_saveStatisticsTimer.cancel(); m_saveStatisticsTimer.cancel();
m_avatarLockTimer.cancel(); m_loginLockTimer.cancel();
} }
void void
@@ -931,6 +931,23 @@ ServerLobbyThread::HandleNetPacketInit(SessionWrapper session, const InitMessage
{ {
LOG_VERBOSE("Received init for session #" << session.sessionData->GetId() << "."); LOG_VERBOSE("Received init for session #" << session.sessionData->GetId() << ".");
// Before any other processing, perform some denial of service and
// brute force attack prevention by checking whether the user recently sent an
// Init packet.
bool recentlySentInit = false;
{
boost::mutex::scoped_lock lock(m_timerClientAddressMapMutex);
if (m_timerClientAddressMap.find(session.sessionData->GetClientAddr()) != m_timerClientAddressMap.end())
recentlySentInit = true;
else
m_timerClientAddressMap[session.sessionData->GetClientAddr()] = boost::timers::portable::microsec_timer();
}
if (recentlySentInit)
{
SessionError(session, ERR_NET_INIT_BLOCKED);
return;
}
// Check the protocol version. // Check the protocol version.
if (initMessage.requestedVersion.major != NET_VERSION_MAJOR if (initMessage.requestedVersion.major != NET_VERSION_MAJOR
|| session.playerData) // Has this session already sent an init? || session.playerData) // Has this session already sent an init?
@@ -1351,16 +1368,7 @@ ServerLobbyThread::InitAfterLogin(SessionWrapper session)
if (!avatarMD5.IsZero() if (!avatarMD5.IsZero()
&& !GetAvatarManager().GetAvatarFileName(avatarMD5, avatarFileName)) && !GetAvatarManager().GetAvatarFileName(avatarMD5, avatarFileName))
{ {
bool avatarRecentlyRequested = false; RequestPlayerAvatar(session);
{
boost::mutex::scoped_lock lock(m_timerAvatarClientAddressMapMutex);
if (m_timerAvatarClientAddressMap.find(session.sessionData->GetClientAddr()) != m_timerAvatarClientAddressMap.end())
avatarRecentlyRequested = true;
}
if (avatarRecentlyRequested)
SessionError(session, ERR_NET_AVATAR_UPLOAD_BLOCKED);
else
RequestPlayerAvatar(session);
} }
else else
{ {
@@ -1429,11 +1437,6 @@ ServerLobbyThread::RequestPlayerAvatar(SessionWrapper session)
{ {
if (!session.playerData.get()) if (!session.playerData.get())
throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0); throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
// Accept no more new avatars from that client for a certain time.
{
boost::mutex::scoped_lock lock(m_timerAvatarClientAddressMapMutex);
m_timerAvatarClientAddressMap[session.sessionData->GetClientAddr()] = boost::timers::portable::microsec_timer();
}
// Ask the client to send its avatar. // Ask the client to send its avatar.
boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc)); boost::shared_ptr<NetPacket> packet(new NetPacket(NetPacket::Alloc));
packet->GetMsg()->present = PokerTHMessage_PR_avatarRequestMessage; packet->GetMsg()->present = PokerTHMessage_PR_avatarRequestMessage;
@@ -1501,29 +1504,29 @@ ServerLobbyThread::TimerRemovePlayer(const boost::system::error_code &ec)
} }
void void
ServerLobbyThread::TimerUpdateClientAvatarLock(const boost::system::error_code &ec) ServerLobbyThread::TimerUpdateClientLoginLock(const boost::system::error_code &ec)
{ {
if (!ec) if (!ec)
{ {
boost::mutex::scoped_lock lock(m_timerAvatarClientAddressMapMutex); boost::mutex::scoped_lock lock(m_timerClientAddressMapMutex);
TimerClientAddressMap::iterator i = m_timerAvatarClientAddressMap.begin(); TimerClientAddressMap::iterator i = m_timerClientAddressMap.begin();
TimerClientAddressMap::iterator end = m_timerAvatarClientAddressMap.end(); TimerClientAddressMap::iterator end = m_timerClientAddressMap.end();
while (i != end) while (i != end)
{ {
TimerClientAddressMap::iterator next = i; TimerClientAddressMap::iterator next = i;
++next; ++next;
if (i->second.elapsed().total_seconds() > SERVER_INIT_AVATAR_CLIENT_LOCK_SEC) if (i->second.elapsed().total_seconds() > SERVER_INIT_LOGIN_CLIENT_LOCK_SEC)
m_timerAvatarClientAddressMap.erase(i); m_timerClientAddressMap.erase(i);
i = next; i = next;
} }
// Restart timer // Restart timer
m_avatarLockTimer.expires_from_now( m_loginLockTimer.expires_from_now(
boost::posix_time::milliseconds(SERVER_UPDATE_AVATAR_LOCK_INTERVAL_MSEC)); boost::posix_time::milliseconds(SERVER_UPDATE_LOGIN_LOCK_INTERVAL_MSEC));
m_avatarLockTimer.async_wait( m_loginLockTimer.async_wait(
boost::bind( boost::bind(
&ServerLobbyThread::TimerUpdateClientAvatarLock, shared_from_this(), boost::asio::placeholders::error)); &ServerLobbyThread::TimerUpdateClientLoginLock, shared_from_this(), boost::asio::placeholders::error));
} }
} }
+4 -4
View File
@@ -147,7 +147,7 @@ protected:
void RequestPlayerAvatar(SessionWrapper session); void RequestPlayerAvatar(SessionWrapper session);
void TimerRemoveGame(const boost::system::error_code &ec); void TimerRemoveGame(const boost::system::error_code &ec);
void TimerRemovePlayer(const boost::system::error_code &ec); void TimerRemovePlayer(const boost::system::error_code &ec);
void TimerUpdateClientAvatarLock(const boost::system::error_code &ec); void TimerUpdateClientLoginLock(const boost::system::error_code &ec);
void TimerCheckSessionTimeouts(const boost::system::error_code &ec); void TimerCheckSessionTimeouts(const boost::system::error_code &ec);
void TimerCleanupAvatarCache(const boost::system::error_code &ec); void TimerCleanupAvatarCache(const boost::system::error_code &ec);
@@ -200,8 +200,8 @@ private:
Gsasl *m_authContext; Gsasl *m_authContext;
TimerClientAddressMap m_timerAvatarClientAddressMap; TimerClientAddressMap m_timerClientAddressMap;
mutable boost::mutex m_timerAvatarClientAddressMapMutex; mutable boost::mutex m_timerClientAddressMapMutex;
RemoveGameList m_removeGameList; RemoveGameList m_removeGameList;
mutable boost::mutex m_removeGameListMutex; mutable boost::mutex m_removeGameListMutex;
@@ -240,7 +240,7 @@ private:
boost::asio::deadline_timer m_sessionTimeoutTimer; boost::asio::deadline_timer m_sessionTimeoutTimer;
boost::asio::deadline_timer m_avatarCleanupTimer; boost::asio::deadline_timer m_avatarCleanupTimer;
boost::asio::deadline_timer m_saveStatisticsTimer; boost::asio::deadline_timer m_saveStatisticsTimer;
boost::asio::deadline_timer m_avatarLockTimer; boost::asio::deadline_timer m_loginLockTimer;
const boost::posix_time::ptime m_startTime; const boost::posix_time::ptime m_startTime;
+1 -1
View File
@@ -83,7 +83,7 @@
#define ERR_NET_GAME_TERMINATION_FAILED 129 #define ERR_NET_GAME_TERMINATION_FAILED 129
#define ERR_NET_INTERNAL_GAME_ERROR 130 #define ERR_NET_INTERNAL_GAME_ERROR 130
#define ERR_NET_DEALER_NOT_FOUND 131 #define ERR_NET_DEALER_NOT_FOUND 131
#define ERR_NET_AVATAR_UPLOAD_BLOCKED 132 #define ERR_NET_INIT_BLOCKED 132
#define ERR_NET_GSASL_INIT_FAILED 133 #define ERR_NET_GSASL_INIT_FAILED 133
#define ERR_NET_GSASL_NO_SCRAM 134 #define ERR_NET_GSASL_NO_SCRAM 134
#define ERR_NET_DB_CONNECT_FAILED 135 #define ERR_NET_DB_CONNECT_FAILED 135
+4 -4
View File
@@ -90,8 +90,8 @@ static asn_INTEGER_enum_map_t asn_MAP_errorReason_value2enum_2[] = {
{ 4, 24, "errorInitPlayerNameInUse" }, { 4, 24, "errorInitPlayerNameInUse" },
{ 5, 26, "errorInitInvalidPlayerName" }, { 5, 26, "errorInitInvalidPlayerName" },
{ 6, 26, "errorInitServerMaintenance" }, { 6, 26, "errorInitServerMaintenance" },
{ 7, 19, "errorAvatarTooLarge" }, { 7, 16, "errorInitBlocked" },
{ 8, 24, "errorAvatarUploadBlocked" }, { 8, 19, "errorAvatarTooLarge" },
{ 256, 18, "errorInvalidPacket" }, { 256, 18, "errorInvalidPacket" },
{ 257, 17, "errorInvalidState" }, { 257, 17, "errorInvalidState" },
{ 258, 21, "errorKickedFromServer" }, { 258, 21, "errorKickedFromServer" },
@@ -99,10 +99,10 @@ static asn_INTEGER_enum_map_t asn_MAP_errorReason_value2enum_2[] = {
{ 260, 19, "errorSessionTimeout" } { 260, 19, "errorSessionTimeout" }
}; };
static unsigned int asn_MAP_errorReason_enum2value_2[] = { static unsigned int asn_MAP_errorReason_enum2value_2[] = {
7, /* errorAvatarTooLarge(7) */ 8, /* errorAvatarTooLarge(8) */
8, /* errorAvatarUploadBlocked(8) */
12, /* errorBannedFromServer(259) */ 12, /* errorBannedFromServer(259) */
3, /* errorInitAuthFailure(3) */ 3, /* errorInitAuthFailure(3) */
7, /* errorInitBlocked(7) */
5, /* errorInitInvalidPlayerName(5) */ 5, /* errorInitInvalidPlayerName(5) */
4, /* errorInitPlayerNameInUse(4) */ 4, /* errorInitPlayerNameInUse(4) */
2, /* errorInitServerFull(2) */ 2, /* errorInitServerFull(2) */
+2 -2
View File
@@ -28,8 +28,8 @@ typedef enum errorReason {
errorReason_errorInitPlayerNameInUse = 4, errorReason_errorInitPlayerNameInUse = 4,
errorReason_errorInitInvalidPlayerName = 5, errorReason_errorInitInvalidPlayerName = 5,
errorReason_errorInitServerMaintenance = 6, errorReason_errorInitServerMaintenance = 6,
errorReason_errorAvatarTooLarge = 7, errorReason_errorInitBlocked = 7,
errorReason_errorAvatarUploadBlocked = 8, errorReason_errorAvatarTooLarge = 8,
errorReason_errorInvalidPacket = 256, errorReason_errorInvalidPacket = 256,
errorReason_errorInvalidState = 257, errorReason_errorInvalidState = 257,
errorReason_errorKickedFromServer = 258, errorReason_errorKickedFromServer = 258,