better oci error reporting

This commit is contained in:
DarthArgus
2016-09-26 06:27:53 +00:00
parent 1651feb4de
commit 41639d8156
8 changed files with 118 additions and 72 deletions
@@ -57,13 +57,16 @@ ClientConnection::~ClientConnection()
void ClientConnection::onConnectionClosed()
{
// client has disconnected
DEBUG_REPORT_LOG(true, ("Client %lu disconnected\n", getStationId()));
LOG("LoginClientConnection", ("onConnectionClosed() for stationId (%lu) at IP (%s)", m_stationId, getRemoteAddress().c_str()));
LoginServer::getInstance().removeClient(m_clientId);
if (!m_isValidated)
if (m_clientId)
{
SessionApiClient * session = LoginServer::getInstance().getSessionApiClient();
// if it is a 0 they are a dos faggot, most likely
DEBUG_REPORT_LOG(true, ("Client %lu disconnected\n", m_stationId));
LOG("LoginClientConnection", ("onConnectionClosed() for stationId (%lu) at IP (%s)", m_stationId, getRemoteAddress().c_str()));
LoginServer::getInstance().removeClient(m_clientId);
}
if (!m_isValidated) {
SessionApiClient *session = LoginServer::getInstance().getSessionApiClient();
if (session)
session->dropClient(this);
}
@@ -69,7 +69,7 @@ void ConfigLoginServer::install(void)
KEY_INT (centralServicePort, 44452);
KEY_INT (clientServicePort, 44453);
KEY_INT (clientOverflowLimit, 1024 * 8);
KEY_INT (maxClients, 3000);
KEY_INT (maxClients, 250);
KEY_INT (taskServicePort, 44459);
KEY_INT (pingServicePort, 44460);
KEY_INT (httpServicePort, 44490);
@@ -116,6 +116,7 @@ void ConfigLoginServer::install(void)
KEY_BOOL(requireSecureLoginForCsTool, true);
KEY_BOOL(useExternalAuth, false);
KEY_STRING(externalAuthURL, "");
KEY_INT(maxConnectionsPerIP, 2); // assuming 2 people playing in the same household
int index = 0;
char const * result = 0;
@@ -17,14 +17,14 @@ class ConfigLoginServer
int maxClients;
int taskServicePort;
int pingServicePort;
int httpServicePort;
int httpServicePort;
bool validateClientVersion;
bool validateStationKey;
bool doSessionLogin;
bool doConsumption;
bool doConsumption;
const char * sessionServers;
int sessionType;
const char * DSN;
const char * databaseUID;
const char * schemaOwner;
@@ -54,7 +54,7 @@ class ConfigLoginServer
const char * purgeAccountSourceTable;
const char * adminAccountDataTable;
bool allowSkipTutorialToAll;
bool internalBypassOnlineLimit;
int populationExtremelyHeavyThresholdPercent;
@@ -63,11 +63,13 @@ class ConfigLoginServer
int populationMediumThresholdPercent;
int populationLightThresholdPercent;
int csToolPort;
bool requireSecureLoginForCsTool;
bool useExternalAuth;
bool requireSecureLoginForCsTool;
bool useExternalAuth;
const char * externalAuthURL;
int maxConnectionsPerIP;
};
static const uint16 getCentralServicePort();
@@ -82,7 +84,7 @@ class ConfigLoginServer
static const bool getDoConsumption();
static const char * getSessionServers();
static const int getSessionType();
static const int getMaxClients ();
static const char * getPrivateIpMask();
static const char * getDSN();
@@ -105,7 +107,7 @@ class ConfigLoginServer
static void install ();
static void remove ();
static int getNumberOfSessionServers();
static int getNumberOfSessionServers();
static char const * getSessionServer(int index);
static const int getDisconnectSleepTime (void);
static const int getClusterGroup();
@@ -118,24 +120,26 @@ class ConfigLoginServer
static int getPurgePhaseAdvanceDays(int purgePhase);
static const char * getAdminAccountDataTable();
static bool getAllowSkipTutorialToAll();
static bool getInternalBypassOnlineLimit();
static const int getCSToolPort();
static bool getRequireSecureLoginForCsTool();
static bool getRequireSecureLoginForCsTool();
static int getPopulationExtremelyHeavyThresholdPercent();
static int getPopulationVeryHeavyThresholdPercent();
static int getPopulationHeavyThresholdPercent();
static int getPopulationMediumThresholdPercent();
static int getPopulationLightThresholdPercent();
static bool getUseExternalAuth();
static bool getUseExternalAuth();
static const char * getExternalAuthUrl();
// has character creation for this cluster been disabled through config option
static bool isCharacterCreationDisabled(std::string const & cluster);
static stdset<std::string>::fwd const & getCharacterCreationDisabledClusterList();
static stdset<std::string>::fwd const & getCharacterCreationDisabledClusterList();
static const int getMaxConnectionsPerIP();
private:
static Data * data;
@@ -483,6 +487,11 @@ inline const char * ConfigLoginServer::getExternalAuthUrl()
{
return data->externalAuthURL;
}
inline const int ConfigLoginServer::getMaxConnectionsPerIP()
{
return data->maxConnectionsPerIP;
}
// ======================================================================
#endif // _ConfigLoginServer_H
@@ -146,11 +146,11 @@ LoginServer::LoginServer() :
setup.compress = ConfigLoginServer::getCompressClientNetworkTraffic();
setup.useTcp = false;
clientService = new Service(ConnectionAllocator<ClientConnection>(), setup);
clientService = new Service(ConnectionAllocator<ClientConnection>(), setup, ConfigLoginServer::getMaxConnectionsPerIP());
setup.compress = false;
setup.port = ConfigLoginServer::getPingServicePort();
pingService = new Service(ConnectionAllocator<PingConnection>(), setup);
pingService = new Service(ConnectionAllocator<PingConnection>(), setup, ConfigLoginServer::getMaxConnectionsPerIP());
setup.useTcp = true;
if (ConfigLoginServer::getDevelopmentMode())
@@ -246,16 +246,22 @@ ClientConnection* LoginServer::getUnvalidatedClient(int clientId)
void LoginServer::removeClient(int clientId)
{
WARNING_STRICT_FATAL(clientId == 0, ("Tried to remove a client with client id == 0"));
std::map<int, ClientConnection*>::iterator i = m_clientMap.find(clientId);
if (i != m_clientMap.end())
{
if (i->second->getIsValidated())
{
IGNORE_RETURN(m_validatedClientMap.erase(i->second->getStationId()));
}
IGNORE_RETURN(m_clientMap.erase(clientId));
}
if (clientId) // yeah why bother if it's 0 or null? i realize 0 is a valid int but since previously the warning below fired if it was 0....yeah, no
{
std::map<int, ClientConnection*>::iterator i = m_clientMap.find(clientId);
if (i != m_clientMap.end())
{
if (i->second->getIsValidated())
{
IGNORE_RETURN(m_validatedClientMap.erase(i->second->getStationId()));
}
IGNORE_RETURN(m_clientMap.erase(clientId));
}
}
else
{
WARNING_STRICT_FATAL(true, ("Tried to remove a client with client id == 0"));
}
}
//-----------------------------------------------------------------------
@@ -69,25 +69,21 @@ bool DB::OCIServer::checkerr(OCISession const & session, int status)
WARNING(true,("Database error: %.*s",512,errbuf));
LOG("DatabaseError",("Database error: %.*s",512,errbuf));
FATAL(DB::Server::getFatalOnError() || session.getFatalOnError(),("Database error: %.*s",512,errbuf));
return false;
/*
switch (errcode)
switch ((int) errcode)
{
case 1013:
FATAL(true,("Cancelled by user request (ctrl-c or kill signal).\n"));
break;
case 12541:
REPORT_LOG(true,("Database Error - %.*s\n", 512, errbuf));
return false;
default:
FATAL(true,("Unhandled Database Error - %.*s\n", 512, errbuf));
break;
}
*/
}
return false;
}
case OCI_INVALID_HANDLE:
REPORT_LOG(true,("Error - OCI_INVALID_HANDLE\n"));
@@ -24,10 +24,11 @@ ConnectionAllocatorBase::~ConnectionAllocatorBase()
//-----------------------------------------------------------------------
//Service::Service(const ConnectionAllocatorBase & c, const unsigned short port, const int m, const int keepAliveDelay, const std::string & interfaceAddress, const bool compress) :
Service::Service(const ConnectionAllocatorBase & c, const NetworkSetupData & setup) :
Service::Service(const ConnectionAllocatorBase & c, const NetworkSetupData & setup, const int maxConnectionsPerIP) :
connectionAllocator(c.clone()),
m_callback(new MessageDispatch::Callback),
m_tcpServer(0)
m_tcpServer(0),
m_maxConnectionsPerIP(maxConnectionsPerIP)
{
std::string realAddress;
if(setup.bindInterface.length() > 0)
@@ -165,7 +166,7 @@ m_tcpServer(0)
m_maxConnections = setup.maxConnections;
newService(this);
m_callback->connect(*this, &Service::onConnectionClosed);
`->connect(*this, &Service::onConnectionClosed);
}
//-----------------------------------------------------------------------
@@ -214,10 +215,38 @@ void Service::onConnectionOpened(Connection * c)
{
if (c)
{
c->setService(this);
c->onConnectionOpened();
connections.insert(c);
WARNING((connections.size() >= static_cast<size_t>(m_maxConnections)), ("Service has reached it's maximum connection count %d", m_maxConnections));
if (connections.size() < static_cast<size_t>(m_maxConnections) || m_maxConnections == 0)
{
std::string remoteIP = c->getRemoteAddress();
int numConnections = 0;
// if we're trying to throttle dos attempts
if (m_maxConnectionsPerIP > 0)
{
// we have to recount each time so that we don't cut off legit users
for (auto i = connections.begin(); i != connections.end(); ++i) {
if (remoteIP == (*i)->getRemoteAddress()) {
numConnections++;
}
}
}
if (m_maxConnectionsPerIP == 0 || (numConnections < m_maxConnectionsPerIP))
{
c->setService(this);
c->onConnectionOpened();
connections.insert(c);
}
else
{
WARNING(true, ("Client at IP %s has attempted more connections than allowed (%i). Potential DoS Attack?", remoteIP.c_str(), m_maxConnectionsPerIP));
removeConnection(c); // asshole (probably)
}
}
else
{
WARNING(true, ("Service has reached it's maximum connection count (%d).", m_maxConnections));
}
}
}
@@ -260,6 +289,7 @@ int Service::flushAndConfirmAllData()
unsigned long startTime = Clock::timeMs();
bool needReport = false;
unsigned long stallReportDelay = ConfigSharedNetwork::getStallReportDelay();
do
{
if(stallReportDelay > 0)
@@ -59,7 +59,7 @@ class Service : public NetworkHandler
{
public:
//Service(const ConnectionAllocatorBase & connectionAllocator, const unsigned short listenPort, const int maxConnections, const int keepAliveDelay = 1000, const std::string & interfaceAddress = std::string(""), const bool compress=false);
Service(const ConnectionAllocatorBase & connectionAllocator, const NetworkSetupData & setupData);
Service(const ConnectionAllocatorBase & connectionAllocator, const NetworkSetupData & setupData, const int maxConnectionsPerIP = 0);
virtual ~Service();
void onConnectionOpened(TcpClient * t);
@@ -86,6 +86,7 @@ private:
const ConnectionAllocatorBase * connectionAllocator;
std::set<Connection *> connections;
int m_maxConnections;
int m_maxConnectionsPerIP; // dos protection for ping and login servers
MessageDispatch::Callback * m_callback;
TcpServer * m_tcpServer;
};
+22 -22
View File
@@ -992,9 +992,9 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e)
if (con == nullptr)
{
// packet coming from an unknown ip/port
// if it is a connection request packet, then establish a new connection object to reply to it
// connection establish packet must always be at least 6 bytes long as we must have a version number, no matter how it changes
// packet coming from an unknown ip/port
// if it is a connection request packet, then establish a new connection object to reply to it
// connection establish packet must always be at least 6 bytes long as we must have a version number, no matter how it changes
if (e->mBuffer[0] == 0 && e->mBuffer[1] == UdpConnection::cUdpPacketConnect && e->mLen == UdpConnection::cUdpPacketConnectSize)
{
if (mConnectionListCount >= mParams.maxConnections)
@@ -1009,8 +1009,8 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e)
mParams.handler->OnConnectRequest(newcon);
if (newcon->GetRefCount() == 1)
{
// we are going to end up destroying this connection when we release it on this next line
// so disconnect it first giving it a reason
// we are going to end up destroying this connection when we release it on this next line
// so disconnect it first giving it a reason
newcon->InternalDisconnect(0, UdpConnection::cDisconnectReasonConnectionRefused);
}
newcon->Release();
@@ -1023,9 +1023,9 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e)
{
if (e->mBuffer[0] == 0 && e->mBuffer[1] == UdpConnection::cUdpPacketRequestRemap)
{
// ok, we got a packet from somebody, that we don't know who they are, but, it appears they are asking
// for their address/port to be remapped. If we allow port (and/or address) remapping, then go ahead
// an honor their request if possible
// ok, we got a packet from somebody, that we don't know who they are, but, it appears they are asking
// for their address/port to be remapped. If we allow port (and/or address) remapping, then go ahead
// an honor their request if possible
uchar *ptr = e->mBuffer + 2;
int connectCode = UdpMisc::GetValue32(ptr);
ptr += 4;
@@ -1036,10 +1036,10 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e)
{
if (mParams.allowAddressRemapping || con->mIp == e->mIp)
{
// one final security check to ensure these are really the same connection, compare encryption codes
// one final security check to ensure these are really the same connection, compare encryption codes
if (con->mConnectionConfig.encryptCode == encryptCode)
{
// remapping is allowed, remap ourselves to the address of the incoming request
// remapping is allowed, remap ourselves to the address of the incoming request
mAddressHashTable->Remove(con, AddressHashValue(con->mIp, con->mPort));
con->mIp = e->mIp;
con->mPort = e->mPort;
@@ -1052,18 +1052,18 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e)
}
// got a packet from somebody and we don't know who they are and the packet we got was not a connection request
// just in case they are a previous client who thinks they are still connected, we will send them an internal
// packet telling them that we don't know who they are
// got a packet from somebody and we don't know who they are and the packet we got was not a connection request
// just in case they are a previous client who thinks they are still connected, we will send them an internal
// packet telling them that we don't know who they are
if (mParams.replyUnreachableConnection)
{
// do not reply back with unreachable if the packet coming in is a terminate or unreachable packet itself
// do not reply back with unreachable if the packet coming in is a terminate or unreachable packet itself
if (e->mBuffer[0] != 0 || (e->mBuffer[0] == 0 && e->mBuffer[1] != UdpConnection::cUdpPacketUnreachableConnection && e->mBuffer[1] != UdpConnection::cUdpPacketTerminate))
{
// since we do not have a connection-object associated with this incoming packet, there is no way we could
// encrypt it or add CRC bytes to it, since we have no idea what the other end of the connection is expecting
// in this regard. As such, the UnreachableConnection packet (like the connect and confirm packets) is one
// of those internal packet types that is designated as not being encrypted or CRC'ed.
// since we do not have a connection-object associated with this incoming packet, there is no way we could
// encrypt it or add CRC bytes to it, since we have no idea what the other end of the connection is expecting
// in this regard. As such, the UnreachableConnection packet (like the connect and confirm packets) is one
// of those internal packet types that is designated as not being encrypted or CRC'ed.
unsigned char buf[8];
buf[0] = 0;
buf[1] = UdpConnection::cUdpPacketUnreachableConnection;
@@ -1389,10 +1389,10 @@ void UdpConnection::InternalDisconnect(int flushTimeout, DisconnectReason reason
return;
}
// send a termination packet to the other side
// do not send a termination packet if we are still negotiating (we are not allowed to send any packets while negotiating)
// if you attempt to send a packet while negotiating, then it will potentially attempt to encrypt it before an encryption
// method is determined, resulting in a function call through an invalid pointer
// send a termination packet to the other side
// do not send a termination packet if we are still negotiating (we are not allowed to send any packets while negotiating)
// if you attempt to send a packet while negotiating, then it will potentially attempt to encrypt it before an encryption
// method is determined, resulting in a function call through an invalid pointer
if (!mSilentDisconnect)
{
if (mStatus == cStatusConnected || mStatus == cStatusDisconnectPending)