From e395177e8f7d5e84337639da0a313cd5b3e773ff Mon Sep 17 00:00:00 2001 From: DarthArgus Date: Mon, 26 Sep 2016 00:29:29 -0500 Subject: [PATCH] this probably has at least one mistake/bug/typo but will move our DoS protection into the low level UDP lib --- .../LoginServer/src/shared/LoginServer.cpp | 1 + .../src/shared/ConfigSharedNetwork.cpp | 7 +++ .../src/shared/ConfigSharedNetwork.h | 1 + .../sharedNetwork/src/shared/Connection.cpp | 2 + .../src/shared/NetworkSetupData.cpp | 1 + .../src/shared/NetworkSetupData.h | 1 + .../sharedNetwork/src/shared/Service.cpp | 45 +++++-------------- .../sharedNetwork/src/shared/Service.h | 3 +- .../3rd/library/udplibrary/UdpLibrary.cpp | 24 ++++++++++ .../3rd/library/udplibrary/UdpLibrary.hpp | 2 +- 10 files changed, 50 insertions(+), 37 deletions(-) diff --git a/engine/server/application/LoginServer/src/shared/LoginServer.cpp b/engine/server/application/LoginServer/src/shared/LoginServer.cpp index 177bfec5..3c91104d 100755 --- a/engine/server/application/LoginServer/src/shared/LoginServer.cpp +++ b/engine/server/application/LoginServer/src/shared/LoginServer.cpp @@ -142,6 +142,7 @@ LoginServer::LoginServer() : NetworkSetupData setup; setup.port = ConfigLoginServer::getClientServicePort(); setup.maxConnections = ConfigLoginServer::getMaxClients(); + setup.maxConnectionsPerIP = ConfigLoginServer::getMaxConnectionsPerIP(); setup.keepAliveDelay = 45000; setup.compress = ConfigLoginServer::getCompressClientNetworkTraffic(); setup.useTcp = false; diff --git a/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.cpp b/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.cpp index 152257e5..663852bb 100755 --- a/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.cpp +++ b/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.cpp @@ -30,6 +30,7 @@ namespace ConfigSharedNetworkNamespace int outgoingBufferSize; int clockSyncDelay; int maxConnections; + int maxConnectionsPerIP; int maxRawPacketSize; int maxInstandingPackets; int maxOutstandingBytes; @@ -506,6 +507,11 @@ bool ConfigSharedNetwork::getLogSendingTooMuchData() return logSendingTooMuchData; } +int ConfigSharedNetwork::getMaxConnectionsPerIP() +{ + return maxConnectionsPerIP; +} + //----------------------------------------------------------------------- void ConfigSharedNetwork::install(int newClockSyncDelay) @@ -518,6 +524,7 @@ void ConfigSharedNetwork::install(int newClockSyncDelay) KEY_INT (incomingBufferSize, 4 * 1024 * 1024); KEY_INT (outgoingBufferSize, 4 * 1024 * 1024); KEY_INT (maxConnections, 1000); + KEY_INT (maxConnectionsPerIP, 0); // unlimited KEY_INT (maxRawPacketSize, 496); KEY_INT (maxInstandingPackets, 400); KEY_INT (maxOutstandingBytes, 200 * 1024); diff --git a/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.h b/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.h index 994aef39..982be453 100755 --- a/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.h +++ b/engine/shared/library/sharedNetwork/src/shared/ConfigSharedNetwork.h @@ -67,6 +67,7 @@ public: static int getNetworkHandlerDispatchThrottleTimeMilliseconds(); static int getNetworkHandlerDispatchQueueSize(); static int getMaxTCPRetries(); + static int getMaxConnectionsPerIP(); static bool getLogSendingTooMuchData(); }; diff --git a/engine/shared/library/sharedNetwork/src/shared/Connection.cpp b/engine/shared/library/sharedNetwork/src/shared/Connection.cpp index c895adba..2a63cb86 100755 --- a/engine/shared/library/sharedNetwork/src/shared/Connection.cpp +++ b/engine/shared/library/sharedNetwork/src/shared/Connection.cpp @@ -22,6 +22,7 @@ #include "sharedNetwork/UdpLibraryMT.h" #include "TcpClient.h" #include "TcpServer.h" +#include "../../../../../../external/3rd/library/udplibrary/UdpLibrary.hpp" #include @@ -206,6 +207,7 @@ m_disconnectReason() p.clockSyncDelay = setup.clockSyncDelay; p.keepAliveDelay = setup.keepAliveDelay; p.maxConnections = 1; + p.maxConnectionsPerIP = setup.maxConnectionsPerIP; p.maxRawPacketSize = setup.maxRawPacketSize; p.maxDataHoldSize = setup.maxDataHoldSize; p.reliable[0].maxInstandingPackets = setup.maxInstandingPackets; diff --git a/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.cpp b/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.cpp index 8a4729d7..822fe4b4 100755 --- a/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.cpp +++ b/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.cpp @@ -18,6 +18,7 @@ outgoingBufferSize(ConfigSharedNetwork::getOutgoingBufferSize()), clockSyncDelay(ConfigSharedNetwork::getClockSyncDelay()), keepAliveDelay(ConfigSharedNetwork::getKeepAliveDelay()), maxConnections(ConfigSharedNetwork::getMaxConnections()), +maxConnectionsPerIP(ConfigSharedNetwork::getMaxConnectionsPerIP()), maxRawPacketSize(ConfigSharedNetwork::getMaxRawPacketSize()), maxInstandingPackets(ConfigSharedNetwork::getMaxInstandingPackets()), maxOutstandingBytes(ConfigSharedNetwork::getMaxOutstandingBytes()), diff --git a/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.h b/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.h index edd00e91..a483055b 100755 --- a/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.h +++ b/engine/shared/library/sharedNetwork/src/shared/NetworkSetupData.h @@ -21,6 +21,7 @@ public: int clockSyncDelay; int keepAliveDelay; int maxConnections; + int maxConnectionsPerIP; int maxRawPacketSize; int maxInstandingPackets; int maxOutstandingBytes; diff --git a/engine/shared/library/sharedNetwork/src/shared/Service.cpp b/engine/shared/library/sharedNetwork/src/shared/Service.cpp index 7558aa29..ef9a1792 100755 --- a/engine/shared/library/sharedNetwork/src/shared/Service.cpp +++ b/engine/shared/library/sharedNetwork/src/shared/Service.cpp @@ -24,11 +24,10 @@ 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, const int maxConnectionsPerIP) : +Service::Service(const ConnectionAllocatorBase & c, const NetworkSetupData & setup) : connectionAllocator(c.clone()), m_callback(new MessageDispatch::Callback), -m_tcpServer(0), -m_maxConnectionsPerIP(maxConnectionsPerIP) +m_tcpServer(0) { std::string realAddress; if(setup.bindInterface.length() > 0) @@ -93,12 +92,12 @@ m_maxConnectionsPerIP(maxConnectionsPerIP) p.icmpErrorRetryPeriod = setup.icmpErrorRetryPeriod; p.maxDataHoldSize = setup.maxDataHoldSize; p.allowPortRemapping = setup.allowPortRemapping; - + p.maxConnectionsPerIP = setup.maxconnectionsPerIP; - if(realAddress.length() > 0) - { - strncpy(p.bindIpAddress, realAddress.c_str(), sizeof(p.bindIpAddress)); - } + if (realAddress.length() > 0) + { + strncpy(p.bindIpAddress, realAddress.c_str(), sizeof(p.bindIpAddress)); + } p.reliable[0].maxInstandingPackets = setup.maxInstandingPackets; p.reliable[0].maxOutstandingBytes = setup.maxOutstandingBytes; @@ -215,33 +214,11 @@ void Service::onConnectionOpened(Connection * c) { if (c) { - if (connections.size() < static_cast(m_maxConnections) || m_maxConnections == 0) + if (connections.size() < static_cast(m_maxConnections)) { - 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) - } + c->setService(this); + c->onConnectionOpened(); + connections.insert(c); } else { diff --git a/engine/shared/library/sharedNetwork/src/shared/Service.h b/engine/shared/library/sharedNetwork/src/shared/Service.h index f32d4d06..c300c0bb 100755 --- a/engine/shared/library/sharedNetwork/src/shared/Service.h +++ b/engine/shared/library/sharedNetwork/src/shared/Service.h @@ -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, const int maxConnectionsPerIP = 0); + Service(const ConnectionAllocatorBase & connectionAllocator, const NetworkSetupData & setupData); virtual ~Service(); void onConnectionOpened(TcpClient * t); @@ -86,7 +86,6 @@ private: const ConnectionAllocatorBase * connectionAllocator; std::set connections; int m_maxConnections; - int m_maxConnectionsPerIP; // dos protection for ping and login servers MessageDispatch::Callback * m_callback; TcpServer * m_tcpServer; }; diff --git a/external/3rd/library/udplibrary/UdpLibrary.cpp b/external/3rd/library/udplibrary/UdpLibrary.cpp index 66440c3d..a2db25af 100755 --- a/external/3rd/library/udplibrary/UdpLibrary.cpp +++ b/external/3rd/library/udplibrary/UdpLibrary.cpp @@ -174,6 +174,7 @@ UdpManager::Params::Params() portAliveDelay = 0; noDataTimeout = 0; maxConnections = 10; + maxConnectionsPerIP = 0; port = 0; portRange = 0; pooledPacketMax = 1000; @@ -997,8 +998,31 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e) // 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 (mParams.maxConnectionsPerIP > 0) + { + UdpConnection *alreadyExists; + + int clientConnections = 0; + for (int i = 1; i != 65535; i++) + { + alreadyExists = AddressGetConnection(e->mIp, i); + if (alreadyExists != nullptr) + { + clientConnections++; + } + } + + if (clientConnections >= mParams.maxConnectionsPerIP) + { + printf("Possible DoS attempt? Client %i attempted more connections than the limit (%i). Dropping!", e->mIp, mParams.maxConnectionsPerIP); + return; + } + } + if (mConnectionListCount >= mParams.maxConnections) + { return; // can't handle any more connections, so ignore this request entirely + } int protocolVersion = UdpMisc::GetValue32(e->mBuffer + 2); if (protocolVersion == cProtocolVersion) diff --git a/external/3rd/library/udplibrary/UdpLibrary.hpp b/external/3rd/library/udplibrary/UdpLibrary.hpp index 39f05a43..469cf159 100644 --- a/external/3rd/library/udplibrary/UdpLibrary.hpp +++ b/external/3rd/library/udplibrary/UdpLibrary.hpp @@ -482,7 +482,7 @@ class UdpManager // is little harm in setting this number larger. // default = 10 int maxConnections; - + int maxConnectionsPerIP; // this is the port number that this manager will use for all incoming and outgoing data. On the client side // this is typically set to 0, which causes the manager object to randomly pick an available port. On the server // side, this port should be set to a specific value as it will represent the port number that clients will use