Implementing some brute force attack and denial of service countermeasure.
This commit is contained in:
+2
-2
@@ -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),
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Vendored
+4
-4
@@ -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) */
|
||||||
|
|||||||
Vendored
+2
-2
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user