From 2ea868bdb62429c600d63beb33c3d97f33023e17 Mon Sep 17 00:00:00 2001 From: DarthArgus Date: Thu, 29 Sep 2016 07:30:07 +0000 Subject: [PATCH] implement proper blacklisting at the lowest possible level, with strikes so that people repeatedly hitting enter with connection issues don't get insta banned --- .../3rd/library/udplibrary/UdpLibrary.cpp | 75 ++++++++++++++----- .../3rd/library/udplibrary/UdpLibrary.hpp | 18 ++++- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/external/3rd/library/udplibrary/UdpLibrary.cpp b/external/3rd/library/udplibrary/UdpLibrary.cpp index 096cee4f..580fd218 100755 --- a/external/3rd/library/udplibrary/UdpLibrary.cpp +++ b/external/3rd/library/udplibrary/UdpLibrary.cpp @@ -4,6 +4,10 @@ #include #include +#include +#include +#include + #include "UdpLibrary.hpp" #if defined(WIN32) @@ -39,8 +43,6 @@ #include #include #include // needed by gcc 3.1 for linux -#include -#include const int INVALID_SOCKET = 0xFFFFFFFF; const int SOCKET_ERROR = 0xFFFFFFFF; @@ -408,8 +410,10 @@ UdpManager::~UdpManager() delete mAddressHashTable; mIpConnectionCount.clear(); + blacklist.clear(); delete mConnectCodeHashTable; delete mPriorityQueue; + for (int i = 0; i < mParams.packetHistoryMax; i++) { delete mPacketHistory[i]; @@ -818,15 +822,22 @@ UdpManager::PacketHistoryEntry *UdpManager::ActualReceive() if (res != SOCKET_ERROR) { - if (mParams.simulateIncomingLossPercent > 0 && ((rand() % 100) < mParams.simulateIncomingLossPercent)) - return(nullptr); // packet, what packet? + // no need in creating objects or processing anything if they are a DoS Attacker! + if (isBlacklisted(addr_from.sin_addr.s_addr)) + { + return nullptr; // send them to the black hole + } - if (mParams.simulateIncomingByteRate > 0) - mSimulateNextIncomingTime = UdpMisc::Clock() + (res * 1000 / mParams.simulateIncomingByteRate); + if (mParams.simulateIncomingLossPercent > 0 && ((rand() % 100) < mParams.simulateIncomingLossPercent)) + return(nullptr); // packet, what packet? - mLastReceiveTime = UdpMisc::Clock(); - mPacketHistory[pos]->mLen = res; + if (mParams.simulateIncomingByteRate > 0) + mSimulateNextIncomingTime = UdpMisc::Clock() + (res * 1000 / mParams.simulateIncomingByteRate); + + + mLastReceiveTime = UdpMisc::Clock(); mPacketHistory[pos]->mIp = UdpIpAddress(addr_from.sin_addr.s_addr); + mPacketHistory[pos]->mLen = res; mPacketHistory[pos]->mPort = (int)ntohs(addr_from.sin_port); mPacketHistoryPosition = (mPacketHistoryPosition + 1) % mParams.packetHistoryMax; @@ -1023,23 +1034,33 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e) { if (mParams.maxConnectionsPerIP > 0) { - if (mIpConnectionCount[e->mIp.GetAddress()] >= mParams.maxConnectionsPerIP) + unsigned int clientAddr = e->mIp.GetAddress(); + + if (mIpConnectionCount[clientAddr] >= mParams.maxConnectionsPerIP) { - std::ofstream log_file("logs/udpDos.log", std::ios_base::out | std::ios_base::app ); - log_file << "UdpLibrary : Potential DoS Attack! Client at IP " << e->mIp.GetV4Address() << " tried to exceed maxConnectionsPerIP (" << mParams.maxConnectionsPerIP << "). Silently disconnecting.\n" << std::end; + if (!isBlacklisted(clientAddr)) + { + // add a strike - if they hit strikeOut then they're banned til next restart + blacklist[clientAddr]++; - con->InternalDisconnect(0, UdpConnection::cDisconnectDosAsshole); - con->SetSilentDisconnect(true); // screw you, jerk - con->Release(); + // log it - later parse this, cross reference, and block in iptables + extern const char *__progname; + const std::string prog(__progname); + static const std::string filename = "logs/udpDos-" + prog + ".log"; + std::ofstream log_file(filename, std::ios_base::out | std::ios_base::app ); + log_file << "Ignoring potential DoS attack from " << e->mIp.GetV4Address() << " (strike " << blacklist[clientAddr] << " of " << strikeOut << ")\n"; + log_file.close(); + } + return; } } if (mConnectionListCount >= mParams.maxConnections) - { - return; // can't handle any more connections, so ignore this request entirely - } + { + return; // can't handle any more connections, so ignore this request entirely + } int protocolVersion = UdpMisc::GetValue32(e->mBuffer + 2); if (protocolVersion == cProtocolVersion) @@ -1120,6 +1141,24 @@ void UdpManager::ProcessRawPacket(const PacketHistoryEntry *e) con->Release(); } +bool UdpManager::isBlacklisted(unsigned int clientAddr) +{ + return (blacklist[clientAddr] == strikeOut); +} + +void UdpManager::disconnectByIp(unsigned int clientAddr) +{ + while (mConnectionList != nullptr) + { + if (mConnectionList->mIp.GetAddress() == clientAddr) + { + mConnectionList->SetSilentDisconnect(true); + mConnectionList->InternalDisconnect(0, UdpConnection::cDisconnectReasonDosAttack); + + } + } +} + UdpConnection *UdpManager::AddressGetConnection(UdpIpAddress ip, int port) const { UdpConnection *found = static_cast(mAddressHashTable->FindFirst(AddressHashValue(ip, port))); @@ -2939,7 +2978,7 @@ const char *UdpConnection::DisconnectReasonText(DisconnectReason reason) sDisconnectReason[cDisconnectReasonMutualConnectError] = "DisconnectReasonConnectError"; sDisconnectReason[cDisconnectReasonConnectingToSelf] = "DisconnectReasonConnectingToSelf"; sDisconnectReason[cDisconnectReasonReliableOverflow] = "DisconnectReasonReliableOverflow"; - sDisconnectReason[cDisconnectDosAsshole] = "DisconnectAssholeDosAttempt"; + sDisconnectReason[cDisconnectReasonDosAttack] = "DisconnectReasonDoSAttack"; } return(sDisconnectReason[reason]); diff --git a/external/3rd/library/udplibrary/UdpLibrary.hpp b/external/3rd/library/udplibrary/UdpLibrary.hpp index d2d5af69..5d99b447 100644 --- a/external/3rd/library/udplibrary/UdpLibrary.hpp +++ b/external/3rd/library/udplibrary/UdpLibrary.hpp @@ -3,6 +3,7 @@ #include #include + #include "UdpHandler.hpp" #include "priority.hpp" #include "hashtable.hpp" @@ -925,6 +926,9 @@ class UdpManager // to explicitly call this function. LogicalPacket *CreatePacket(const void *data, int dataLen, const void *data2 = nullptr, int dataLen2 = 0); + // is the given unsigned int expressed ip blacklisted? + bool isBlacklisted(unsigned int); + protected: friend class PooledLogicalPacket; void PoolReturn(PooledLogicalPacket *packet); // so pooled packets can add themselves back to the pool @@ -1041,7 +1045,19 @@ class UdpManager // typically it is recommended that all UdpConnection objects be destroyed before destroying this manager object int mRefCount; + + // number of strikes + static const int strikeOut = 3; + + // actual count of connections for a given ip std::unordered_map mIpConnectionCount; + + + // count of strikes against a given ip - 3 successive DoS attempts and they are banned til next restart at best + std::unordered_map blacklist; + + // does what it says + void disconnectByIp (unsigned int); }; //////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1059,7 +1075,7 @@ class UdpConnection : public PriorityQueueMember, public AddressHashTableMember, , cDisconnectReasonNewConnectionAttempt, cDisconnectReasonConnectionRefused , cDisconnectReasonMutualConnectError, cDisconnectReasonConnectingToSelf , cDisconnectReasonReliableOverflow - , cDisconnectReasonCount, cDisconnectDosAsshole }; + , cDisconnectReasonCount, cDisconnectReasonDosAttack }; // standard AddRef/Release scheme void AddRef();