Flood Koruma Sistemi [ddos saldırısı]

  • Konuyu açan Konuyu açan Sys
  • Açılış Tarihi Açılış Tarihi
  • Yanıt Yanıt 11
  • Gösterim Gösterim 534

Sys

MT Üye
MT Üye
Mesaj
172
Çözümler
4
Beğeni
236
Puan
734
Ticaret Puanı
0

Merhaba mmotutkunlari 😄

Sunucunuza dakikada 500 tane “selamun aleyküm ben geldim” diyen floodçular yüzünden kanallar mı düşüyor? Oyuncular giremiyor mu?
Artık bu sadece saldırı alan kişilerin değil, **topluluk olarak hepimizin sorunu**.


Bazı kendini bilmez terbiyesizler yüzünden yeni sunucu açan, koruma alamayan birçok kişi mağdur durumda.
Diğer forumda bir çözüm görmüştüm ama… açık konuşayım, *aşırı basitti*, içime sinmedi.
“Bu böyle mi yapılır ya?” dedim, oturdum düzenledim.



1749413804503.webp


- Aynı IP'den kısa sürede çok fazla bağlantı denemesi yapılırsa, **otomatik ban** atılıyor.
- Banlar ram üzerinde tutuluyor oyunu yeniden başlatana kadar giriş yapamaz.
- Engellenen IP’ler Oyuncu ışınlandığında vs gibi durumlarda oyundan sessizce düşüyor.
- Kodlar tamamen native C++


Bir video bırakayım.




Not: Kullandığım Altyapı Martysama p23 sürümü Kodları direkt olarak değişen dosya bazlı verdim, çünkü çoğu kişi WinMerge kullanıyor aktarması daha kolay olur olarak düşündüm. İleride umarım Arat ekle olarak güncellerim :D

--- Not :Bir kaç kısımı yeniden düzenledim Çıkan sorun ve hataları bildirirseniz ona göre düzenleyip daha düzgün bir yapı oluşturabilirim katkı vermek isteyen olursa forum üzerinden iletişime geçebilir.



Yeni güncelleme



Link:
Linkleri görebilmek için giriş yap veya kayıt ol.
 
Son düzenleme:
Şu anki hâlini biraz daha geliştirdim; tüm sistemi bir #define içine alarak daha stabil ve kontrol edilebilir bir yapıya kavuşturdum.


GitHub üzerinden paylaştım.

Not:
🛑 Lütfen ilk versiyonu kullanmayın, çünkü:

  • İlk sürümde flood saldırısı sona erse bile kanallar kapalı kalabiliyordu.

Bu yüzden güncelleme yapma kararı aldım.


❗ Eski Durum (Flood Sırasında):​


  • AcceptDesc() fonksiyonunda IP limiti doluyordu.
  • Sunucu socket_close() yapıyordu.
  • Client connect() başaramıyordu → kanal (kapalı ) görünüyordu.

✅ Yeni Durum (Flood Bittikten Sonra):​


  • Yeni gelen bağlantılar AcceptDesc() kontrolünden geçebiliyor.
  • Saldırı Bitince Her şey normal haline dönüyor
  • connect() başarılı → Client kanalı açık olarak algılıyor.



Şu anki sistem, hem koruma sağlıyor hem de kullanıcı deneyimini bozmuyor.
Bunu böyle yapsan veya bunu da ekleseydin daha iyi olurdu gibi önerilere açığım.
Herkese iyi forumlar diliyorum.
 
teşekkürler güzel paylaşım bunu ipfrw ile yapıyoruz ama çogu makinaya kural girince ssh dahil bütün baglantıyı kesebiliyor. Dc almadıysan bekle ki destek dönsün :D
 
bir fileste dikkatimi çekmişti hazır burda böyle bir konu varken yazmak istiyorum bu ne işe yarıyor? ve ne kadar etkili


Kod:
Genişlet Daralt Kopyala
#if defined(__IMPROVED_HANDSHAKE_PROCESS__)
/*
* Title: Improved Handshake Process
* Description: An Anti-spam solution that limits the amount
*              of handshakes per second and per attempts.
* Date: YMD.2021.09.07
* Author: Owsap, OSP (Owsap Server Protection)
*
* Copyright 2021 Owsap Productions
*/
void DESC_MANAGER::AcceptHandshake(const char* c_szHost, DWORD dwHandshakeTime)
{
    // Find if the host is in the AcceptHostHandshakeVector
    auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Check if host already exists in the AcceptHostHandshakeVector
    if (it != m_vecAcceptHostHandshake.end())
    {
        // Check if the cores pulse is greater than the last handshake time set @ DESC::Setup
        if (thecore_pulse() > it->second)
            m_vecAcceptHostHandshake.erase(it);
    }
    else // Set host handshake time
        m_vecAcceptHostHandshake.emplace_back(std::make_pair(c_szHost, dwHandshakeTime));
}

bool DESC_MANAGER::IsIntrusiveHandshake(const char* c_szHost)
{
    if (!m_vecAcceptHostHandshake.empty())
    {
        // Find if the host is in the AcceptHostHandshakeVector and if the cores
        // pulse is greater than the last handshake time set @ DESC::Setup
        auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecAcceptHostHandshake.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::SetIntrusiveCount(const char* c_szHost, bool bReset)
{
    // Find if the host is in the IntrusiveHostCountVector
    auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intrusive host count if exists in the IntrusiveHostCountVector
    if (it != m_vecIntrusiveHostCount.end())
    {
        if (bReset)
            it->second = 0;
        else
            it->second = it->second + 1;
    }
    else
        // Emplace the host into the IntrusiveHostCountVector with count set to 1
        m_vecIntrusiveHostCount.emplace_back(std::make_pair(c_szHost, 1));
}

int DESC_MANAGER::GetIntrusiveCount(const char* c_szHost)
{
    if (!m_vecIntrusiveHostCount.empty())
    {
        // Find if the host is in the IntrusiveHostCountVector
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        // Return the intrusive host count
        if (it != m_vecIntrusiveHostCount.end())
            return it->second;
    }
    return 0;
}

void DESC_MANAGER::SetIntruder(const char* c_szHost, DWORD dwDelayHandshakeTime)
{
    // Reset intrusive host count
    SetIntrusiveCount(c_szHost, true /* reset */);

    // Find if the host is in the IntruderHostVector
    auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intruder host with the next (delayed) handshake time
    if (it != m_vecIntruderHost.end())
        it->second = dwDelayHandshakeTime;
    else
        // Emplace the host into the IntruderHostVector with the next (delayed) handshake time
        m_vecIntruderHost.emplace_back(std::make_pair(c_szHost, dwDelayHandshakeTime));
}

bool DESC_MANAGER::IsIntruder(const char* c_szHost)
{
    if (!m_vecIntruderHost.empty())
    {
        // Find if the host is in the IntruderHostVector and if the cores pulse
        // is less than the next (delayed) handshake time
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecIntruderHost.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::AllowHandshake(const char* c_szHost)
{
    // Clear the intrusive host count
    if (!m_vecIntrusiveHostCount.empty())
    {
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntrusiveHostCount.end())
            m_vecIntrusiveHostCount.erase(it);
    }

    // Clear the intruder host
    if (!m_vecIntruderHost.empty())
    {
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntruderHost.end())
            m_vecIntruderHost.erase(it);
    }
}
#endif
 

teşekkürler güzel paylaşım bunu ipfrw ile yapıyoruz ama çogu makinaya kural girince ssh dahil bütün baglantıyı kesebiliyor. Dc almadıysan bekle ki destek dönsün :D
Rica ederim. Harun peki opnsense kullandın mı daha önce ? ipfw kendi firewall'i galiba freebsd'nin
Freebsd konularında bilgim yok nasıl bir yol izlemek gerekiyor aydınlatırsan sevinirim.
bir fileste dikkatimi çekmişti hazır burda böyle bir konu varken yazmak istiyorum bu ne işe yarıyor? ve ne kadar etkili


Kod:
Genişlet Daralt Kopyala
#if defined(__IMPROVED_HANDSHAKE_PROCESS__)
/*
* Title: Improved Handshake Process
* Description: An Anti-spam solution that limits the amount
*              of handshakes per second and per attempts.
* Date: YMD.2021.09.07
* Author: Owsap, OSP (Owsap Server Protection)
*
* Copyright 2021 Owsap Productions
*/
void DESC_MANAGER::AcceptHandshake(const char* c_szHost, DWORD dwHandshakeTime)
{
    // Find if the host is in the AcceptHostHandshakeVector
    auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Check if host already exists in the AcceptHostHandshakeVector
    if (it != m_vecAcceptHostHandshake.end())
    {
        // Check if the cores pulse is greater than the last handshake time set @ DESC::Setup
        if (thecore_pulse() > it->second)
            m_vecAcceptHostHandshake.erase(it);
    }
    else // Set host handshake time
        m_vecAcceptHostHandshake.emplace_back(std::make_pair(c_szHost, dwHandshakeTime));
}

bool DESC_MANAGER::IsIntrusiveHandshake(const char* c_szHost)
{
    if (!m_vecAcceptHostHandshake.empty())
    {
        // Find if the host is in the AcceptHostHandshakeVector and if the cores
        // pulse is greater than the last handshake time set @ DESC::Setup
        auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecAcceptHostHandshake.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::SetIntrusiveCount(const char* c_szHost, bool bReset)
{
    // Find if the host is in the IntrusiveHostCountVector
    auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intrusive host count if exists in the IntrusiveHostCountVector
    if (it != m_vecIntrusiveHostCount.end())
    {
        if (bReset)
            it->second = 0;
        else
            it->second = it->second + 1;
    }
    else
        // Emplace the host into the IntrusiveHostCountVector with count set to 1
        m_vecIntrusiveHostCount.emplace_back(std::make_pair(c_szHost, 1));
}

int DESC_MANAGER::GetIntrusiveCount(const char* c_szHost)
{
    if (!m_vecIntrusiveHostCount.empty())
    {
        // Find if the host is in the IntrusiveHostCountVector
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        // Return the intrusive host count
        if (it != m_vecIntrusiveHostCount.end())
            return it->second;
    }
    return 0;
}

void DESC_MANAGER::SetIntruder(const char* c_szHost, DWORD dwDelayHandshakeTime)
{
    // Reset intrusive host count
    SetIntrusiveCount(c_szHost, true /* reset */);

    // Find if the host is in the IntruderHostVector
    auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intruder host with the next (delayed) handshake time
    if (it != m_vecIntruderHost.end())
        it->second = dwDelayHandshakeTime;
    else
        // Emplace the host into the IntruderHostVector with the next (delayed) handshake time
        m_vecIntruderHost.emplace_back(std::make_pair(c_szHost, dwDelayHandshakeTime));
}

bool DESC_MANAGER::IsIntruder(const char* c_szHost)
{
    if (!m_vecIntruderHost.empty())
    {
        // Find if the host is in the IntruderHostVector and if the cores pulse
        // is less than the next (delayed) handshake time
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecIntruderHost.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::AllowHandshake(const char* c_szHost)
{
    // Clear the intrusive host count
    if (!m_vecIntrusiveHostCount.empty())
    {
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntrusiveHostCount.end())
            m_vecIntrusiveHostCount.erase(it);
    }

    // Clear the intruder host
    if (!m_vecIntruderHost.empty())
    {
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntruderHost.end())
            m_vecIntruderHost.erase(it);
    }
}
#endif
Aynı amaca hizmet ediyorlar Aynı IP'den gelen aşırı bağlantı isteklerini (handshake) tespit edip engellemek.
 
Paylaşım için teşekkürler ellerinize sağlık, kurulum için bir rehber yayımlamayı düşünüyor musunuz acaba?
 
Paylaşım için teşekkürler ellerinize sağlık, kurulum için bir rehber yayımlamayı düşünüyor musunuz acaba?
Rica ederim github üzerinden kurulum yapılmış dosyaları paylaştım hocam winmerge veya başka bir tools ile rahat bir şekilde ekliye bilirsiniz.

ENABLE_ADVANCED_FLOOD_PROTECTION definesi
 


Rica ederim. Harun peki opnsense kullandın mı daha önce ? ipfw kendi firewall'i galiba freebsd'nin
Freebsd konularında bilgim yok nasıl bir yol izlemek gerekiyor aydınlatırsan sevinirim.

Aynı amaca hizmet ediyorlar Aynı IP'den gelen aşırı bağlantı isteklerini (handshake) tespit edip engellemek.
opnsense hiç kullanmadım. ipfrw evet freebsd içine kendin kuruyorsun senin mantık, şu kadar ileti gelirse engelle gibi
 
bir fileste dikkatimi çekmişti hazır burda böyle bir konu varken yazmak istiyorum bu ne işe yarıyor? ve ne kadar etkili


Kod:
Genişlet Daralt Kopyala
#if defined(__IMPROVED_HANDSHAKE_PROCESS__)
/*
* Title: Improved Handshake Process
* Description: An Anti-spam solution that limits the amount
*              of handshakes per second and per attempts.
* Date: YMD.2021.09.07
* Author: Owsap, OSP (Owsap Server Protection)
*
* Copyright 2021 Owsap Productions
*/
void DESC_MANAGER::AcceptHandshake(const char* c_szHost, DWORD dwHandshakeTime)
{
    // Find if the host is in the AcceptHostHandshakeVector
    auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Check if host already exists in the AcceptHostHandshakeVector
    if (it != m_vecAcceptHostHandshake.end())
    {
        // Check if the cores pulse is greater than the last handshake time set @ DESC::Setup
        if (thecore_pulse() > it->second)
            m_vecAcceptHostHandshake.erase(it);
    }
    else // Set host handshake time
        m_vecAcceptHostHandshake.emplace_back(std::make_pair(c_szHost, dwHandshakeTime));
}

bool DESC_MANAGER::IsIntrusiveHandshake(const char* c_szHost)
{
    if (!m_vecAcceptHostHandshake.empty())
    {
        // Find if the host is in the AcceptHostHandshakeVector and if the cores
        // pulse is greater than the last handshake time set @ DESC::Setup
        auto it = std::find_if(m_vecAcceptHostHandshake.begin(), m_vecAcceptHostHandshake.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecAcceptHostHandshake.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::SetIntrusiveCount(const char* c_szHost, bool bReset)
{
    // Find if the host is in the IntrusiveHostCountVector
    auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intrusive host count if exists in the IntrusiveHostCountVector
    if (it != m_vecIntrusiveHostCount.end())
    {
        if (bReset)
            it->second = 0;
        else
            it->second = it->second + 1;
    }
    else
        // Emplace the host into the IntrusiveHostCountVector with count set to 1
        m_vecIntrusiveHostCount.emplace_back(std::make_pair(c_szHost, 1));
}

int DESC_MANAGER::GetIntrusiveCount(const char* c_szHost)
{
    if (!m_vecIntrusiveHostCount.empty())
    {
        // Find if the host is in the IntrusiveHostCountVector
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        // Return the intrusive host count
        if (it != m_vecIntrusiveHostCount.end())
            return it->second;
    }
    return 0;
}

void DESC_MANAGER::SetIntruder(const char* c_szHost, DWORD dwDelayHandshakeTime)
{
    // Reset intrusive host count
    SetIntrusiveCount(c_szHost, true /* reset */);

    // Find if the host is in the IntruderHostVector
    auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
        [&c_szHost](const PairedStringDWORD& element)
        { return (element.first == c_szHost); }
    );
    // Set intruder host with the next (delayed) handshake time
    if (it != m_vecIntruderHost.end())
        it->second = dwDelayHandshakeTime;
    else
        // Emplace the host into the IntruderHostVector with the next (delayed) handshake time
        m_vecIntruderHost.emplace_back(std::make_pair(c_szHost, dwDelayHandshakeTime));
}

bool DESC_MANAGER::IsIntruder(const char* c_szHost)
{
    if (!m_vecIntruderHost.empty())
    {
        // Find if the host is in the IntruderHostVector and if the cores pulse
        // is less than the next (delayed) handshake time
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost && element.second > thecore_pulse()); }
        );
        if (it != m_vecIntruderHost.end())
            return true;
    }
    return false;
}

void DESC_MANAGER::AllowHandshake(const char* c_szHost)
{
    // Clear the intrusive host count
    if (!m_vecIntrusiveHostCount.empty())
    {
        auto it = std::find_if(m_vecIntrusiveHostCount.begin(), m_vecIntrusiveHostCount.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntrusiveHostCount.end())
            m_vecIntrusiveHostCount.erase(it);
    }

    // Clear the intruder host
    if (!m_vecIntruderHost.empty())
    {
        auto it = std::find_if(m_vecIntruderHost.begin(), m_vecIntruderHost.end(),
            [&c_szHost](const PairedStringDWORD& element)
            { return (element.first == c_szHost); }
        );
        if (it != m_vecIntruderHost.end())
            m_vecIntruderHost.erase(it);
    }
}
#endif
bu yanlış hatırlamıyorsam owsap'ın sistemi bu sistemde arkadaşımızın yaptıgı gibi gelen baglatıları kontrol ediyor.
 
Biraz bakınırken kalıcı ban sistemi de eklemek geldi aklıma 😄
şuanki mevcut sistem IP ne kadar saldırırsa saldırsın, sadece o anda bağlantısı kesiliyor ama yeniden bağlanmasına engel olunmuyordu.
Alternatif olarak farklı bir sistem de geliştirebilirim diye düşündüm ve aşağıya güncellenmiş dosyaları bıraktım. (Test etme fırsatım olmadı) 😅
Sistemi tam anlamıyla test edemedim. Geri bildirimlere göre güncellemeler yapmak istiyorum fakat aktif oyunlardan henüz dönüş alamadım.
Belki IP kara listesi gibi, giriş aşamasında tamamen engelleyen bir yapı da kurulabilir. Ama son zamanlarda çok vaktim olmuyor bayram sonrası tempo başladı yine :/ genelde sadece "ekledim ama hata alıyorum" tarzında geri dönüşler geliyor 😅


#[F] Aktif oyunlardan Dönüş olursa ona göre güncellemeye devam edeceğim.




desc_manager:
Genişlet Daralt Kopyala
#ifdef ENABLE_ADVANCED_FLOOD_PROTECTION
#include <unordered_set>
#include <mutex>
#include <string>

static std::unordered_set<std::string> permanentlyBannedIPs;
static std::mutex ipBanMutex;

bool IsIPBanned(const std::string& ip) {
    std::lock_guard<std::mutex> lock(ipBanMutex);
    return permanentlyBannedIPs.count(ip) > 0;
}

void BanIP(const std::string& ip) {
    std::lock_guard<std::mutex> lock(ipBanMutex);
    permanentlyBannedIPs.insert(ip);
}
#endif

#include "stdafx.h"
#include "config.h"
#include "utils.h"
#include "crc32.h"
#include "desc.h"
#include "desc_p2p.h"
#include "desc_client.h"
#include "desc_manager.h"
#include "char.h"
#include "protocol.h"
#include "messenger_manager.h"
#include "p2p.h"
#include <boost/algorithm/string.hpp>
#include <msl/msl.h>
#ifdef ENABLE_ADVANCED_FLOOD_PROTECTION
#include <unordered_map>
#include <chrono>
#endif

struct valid_ip
{
    const char* ip;
    BYTE    network;
    BYTE    mask;
};

static struct valid_ip admin_ip[] =
{
    { "210.123.10",     128,    128     },
    { "\n",             0,      0       }
};

int IsValidIP(struct valid_ip* ip_table, const char* host)
{
    int         i, j;
    char        ip_addr[256];

    for (i = 0; *(ip_table + i)->ip != '\n'; ++i)
    {
        j = 255 - (ip_table + i)->mask;

        do
        {
            snprintf(ip_addr, sizeof(ip_addr), "%s.%d", (ip_table + i)->ip, (ip_table + i)->network + j);

            if (!strcmp(ip_addr, host))
            {
                return TRUE;
            }

            if (!j)
            {
                break;
            }
        } while (j--);
    }

    return FALSE;
}

DESC_MANAGER::DESC_MANAGER() : m_bDestroyed(false)
{
    Initialize();
}

DESC_MANAGER::~DESC_MANAGER()
{
    Destroy();
}

void DESC_MANAGER::Initialize()
{
    m_iSocketsConnected = 0;
    m_iHandleCount = 0;
    m_iLocalUserCount = 0;
    memset(m_aiEmpireUserCount, 0, sizeof(m_aiEmpireUserCount));
    m_bDisconnectInvalidCRC = false;
}

void DESC_MANAGER::Destroy()
{
    if (m_bDestroyed)
    {
        return;
    }

    m_bDestroyed = true;

    DESC_SET::iterator i = m_set_pkDesc.begin();

    while (i != m_set_pkDesc.end())
    {
        LPDESC d = *i;
        DESC_SET::iterator ci = i;
        ++i;

        if (d->GetType() == DESC_TYPE_CONNECTOR)
        {
            continue;
        }

        if (d->IsPhase(PHASE_P2P))
        {
            continue;
        }

        DestroyDesc(d, false);
        m_set_pkDesc.erase(ci);
    }

    i = m_set_pkDesc.begin();

    while (i != m_set_pkDesc.end())
    {
        LPDESC d = *i;
        DESC_SET::iterator ci = i;
        ++i;

        DestroyDesc(d, false);
        m_set_pkDesc.erase(ci);
    }

    m_set_pkClientDesc.clear();

    //m_AccountIDMap.clear();
    m_map_loginName.clear();
    m_map_handle.clear();
    Initialize();
}

DWORD DESC_MANAGER::CreateHandshake()
{
    char crc_buf[8];
    crc_t crc;
    DESC_HANDSHAKE_MAP::iterator it;

RETRY:

    do
    {
        DWORD val = msl::random_int(0, 1024 * 1024);

        *(DWORD*)(crc_buf) = val;
        *((DWORD*)crc_buf + 1) = get_global_time();

        crc = GetCRC32(crc_buf, 8);
        it = m_map_handshake.find(crc);
    } while (it != m_map_handshake.end());

    if (crc == 0)
    {
        goto RETRY;
    }

    return (crc);
}

LPDESC DESC_MANAGER::AcceptDesc(LPFDWATCH fdw, socket_t s)
{
    socket_t                    desc;
    LPDESC                        newd;
    static struct sockaddr_in   peer;
    static char                    host[MAX_HOST_LENGTH + 1];

    if ((desc = socket_accept(s, &peer)) == -1)
    {
        return NULL;
    }

    strlcpy(host, inet_ntoa(peer.sin_addr), sizeof(host));

#ifdef ENABLE_ADVANCED_FLOOD_PROTECTION
    {
        auto now = std::chrono::steady_clock::now();
        auto& lastConn = m_ipLastConnTime[host];

        if (std::chrono::duration_cast<std::chrono::seconds>(now - lastConn).count() < 1)
        {
            int& ipCount = m_ipConnectionCount[host];
            ipCount++;

            if (ipCount > 10)
            {
                sys_err("FLOOD: Too many connections from IP %s", host);
                socket_close(desc);
                return NULL;
            }
        }
        else
        {
            m_ipConnectionCount[host] = 1;
            m_ipLastConnTime[host] = now;
        }
    }
#endif

    if (!IsValidIP(admin_ip, host))
    {
        if (m_iSocketsConnected >= MAX_ALLOW_USER)
        {
            sys_err("max connection reached. MAX_ALLOW_USER = %d", MAX_ALLOW_USER);
            socket_close(desc);
            return NULL;
        }
    }

    newd = M2_NEW DESC;
    crc_t handshake = CreateHandshake();

    if (!newd->Setup(fdw, desc, peer, ++m_iHandleCount, handshake))
    {
        socket_close(desc);
        M2_DELETE(newd);
        return NULL;
    }

    m_map_handshake.emplace(handshake, newd);
    m_map_handle.emplace(newd->GetHandle(), newd);

    m_set_pkDesc.emplace(newd);
    ++m_iSocketsConnected;
    return (newd);
}

LPDESC DESC_MANAGER::AcceptP2PDesc(LPFDWATCH fdw, socket_t bind_fd)
{
    socket_t           fd;
    struct sockaddr_in peer;
    char               host[MAX_HOST_LENGTH + 1];

    if ((fd = socket_accept(bind_fd, &peer)) == -1)
    {
        return NULL;
    }

    strlcpy(host, inet_ntoa(peer.sin_addr), sizeof(host));

    LPDESC_P2P pkDesc = M2_NEW DESC_P2P;

    if (!pkDesc->Setup(fdw, fd, host, peer.sin_port))
    {
        sys_err("DESC_MANAGER::AcceptP2PDesc : Setup failed");
        socket_close(fd);
        M2_DELETE(pkDesc);
        return NULL;
    }

    m_set_pkDesc.emplace(pkDesc);
    ++m_iSocketsConnected;

    sys_log(0, "DESC_MANAGER::AcceptP2PDesc  %s:%u", host, peer.sin_port);
    P2P_MANAGER::instance().RegisterAcceptor(pkDesc);
    return (pkDesc);
}

void DESC_MANAGER::ConnectAccount(const std::string& login, LPDESC d)
{
    m_map_loginName.emplace(login, d);
}

void DESC_MANAGER::DisconnectAccount(const std::string& login)
{
    m_map_loginName.erase(login);
}

void DESC_MANAGER::DestroyLoginKey(const std::string_view msg) const
{
    if (msg.empty())
    {
        return;
    }

    TPacketDC p{};
    strlcpy(p.login, msg.data(), sizeof(p.login));
    db_clientdesc->DBPacket(HEADER_GD_DC, 0, p);
}

void DESC_MANAGER::DestroyLoginKey(const LPDESC d) const
{
    if (!d)
    {
        return;
    }

    DestroyLoginKey(d->GetAccountTable().login);
}

void DESC_MANAGER::DestroyDesc(LPDESC d, bool bEraseFromSet)
{
    if (bEraseFromSet)
    {
        m_set_pkDesc.erase(d);
    }

    if (d->GetHandshake())
    {
        m_map_handshake.erase(d->GetHandshake());
    }

    if (d->GetHandle() != 0)
    {
        m_map_handle.erase(d->GetHandle());
    }

    else
    {
        m_set_pkClientDesc.erase((LPCLIENT_DESC)d);
    }

    // Explicit call to the virtual function Destroy()
    d->Destroy();

    M2_DELETE(d);
    --m_iSocketsConnected;
}

void DESC_MANAGER::DestroyClosed()
{
    DESC_SET::iterator i = m_set_pkDesc.begin();

    while (i != m_set_pkDesc.end())
    {
        LPDESC d = *i;
        DESC_SET::iterator ci = i;
        ++i;

        if (d->IsPhase(PHASE_CLOSE))
        {
            if (d->GetType() == DESC_TYPE_CONNECTOR)
            {
                LPCLIENT_DESC client_desc = (LPCLIENT_DESC)d;

                if (client_desc->IsRetryWhenClosed())
                {
                    client_desc->Reset();
                    continue;
                }
            }

            DestroyDesc(d, false);
            m_set_pkDesc.erase(ci);
        }
    }
}

LPDESC DESC_MANAGER::FindByLoginName(const std::string& login)
{
    DESC_LOGINNAME_MAP::iterator it = m_map_loginName.find(login);

    if (m_map_loginName.end() == it)
    {
        return NULL;
    }

    return (it->second);
}

LPDESC DESC_MANAGER::FindByHandle(DWORD handle)
{
    DESC_HANDLE_MAP::iterator it = m_map_handle.find(handle);

    if (m_map_handle.end() == it)
    {
        return NULL;
    }

    return (it->second);
}

const DESC_MANAGER::DESC_SET& DESC_MANAGER::GetClientSet()
{
    return m_set_pkDesc;
}

struct name_with_desc_func
{
    const char* m_name;

    name_with_desc_func(const char* name) : m_name(name)
    {
    }

    bool operator() (LPDESC d)
    {
        if (d->GetCharacter() && !strcmp(d->GetCharacter()->GetName(), m_name))
        {
            return true;
        }

        return false;
    }
};

LPDESC DESC_MANAGER::FindByCharacterName(const char* name)
{
    DESC_SET::iterator it = std::find_if(m_set_pkDesc.begin(), m_set_pkDesc.end(), name_with_desc_func(name));
    return (it == m_set_pkDesc.end()) ? NULL : (*it);
}

LPCLIENT_DESC DESC_MANAGER::CreateConnectionDesc(LPFDWATCH fdw, const char* host, WORD port, int iPhaseWhenSucceed, bool bRetryWhenClosed)
{
    LPCLIENT_DESC newd;

    newd = M2_NEW CLIENT_DESC;

    newd->Setup(fdw, host, port);
    newd->Connect(iPhaseWhenSucceed);
    newd->SetRetryWhenClosed(bRetryWhenClosed);

    m_set_pkDesc.emplace(newd);
    m_set_pkClientDesc.emplace(newd);

    ++m_iSocketsConnected;
    return (newd);
}

struct FuncTryConnect
{
    void operator() (LPDESC d)
    {
        ((LPCLIENT_DESC)d)->Connect();
    }
};

void DESC_MANAGER::TryConnect()
{
    FuncTryConnect f;
    std::for_each(m_set_pkClientDesc.begin(), m_set_pkClientDesc.end(), f);
}

bool DESC_MANAGER::IsP2PDescExist(const char* szHost, WORD wPort)
{
    CLIENT_DESC_SET::iterator it = m_set_pkClientDesc.begin();

    while (it != m_set_pkClientDesc.end())
    {
        LPCLIENT_DESC d = *(it++);

        if (!strcmp(d->GetP2PHost(), szHost) && d->GetP2PPort() == wPort)
        {
            return true;
        }
    }

    return false;
}

LPDESC DESC_MANAGER::FindByHandshake(DWORD dwHandshake)
{
    DESC_HANDSHAKE_MAP::iterator it = m_map_handshake.find(dwHandshake);

    if (it == m_map_handshake.end())
    {
        return NULL;
    }

    return (it->second);
}

class FuncWho
{
public:
    int iTotalCount;
    int aiEmpireUserCount[EMPIRE_MAX_NUM];

    FuncWho()
    {
        iTotalCount = 0;
        memset(aiEmpireUserCount, 0, sizeof(aiEmpireUserCount));
    }

    void operator() (LPDESC d)
    {
        if (d->GetCharacter())
        {
            ++iTotalCount;
            ++aiEmpireUserCount[d->GetEmpire()];
        }
    }
};

void DESC_MANAGER::UpdateLocalUserCount()
{
    const DESC_SET& c_ref_set = GetClientSet();
    FuncWho f;
    f = std::for_each(c_ref_set.begin(), c_ref_set.end(), f);

    m_iLocalUserCount = f.iTotalCount;
    thecore_memcpy(m_aiEmpireUserCount, f.aiEmpireUserCount, sizeof(m_aiEmpireUserCount));

    m_aiEmpireUserCount[1] += P2P_MANAGER::instance().GetEmpireUserCount(1);
    m_aiEmpireUserCount[2] += P2P_MANAGER::instance().GetEmpireUserCount(2);
    m_aiEmpireUserCount[3] += P2P_MANAGER::instance().GetEmpireUserCount(3);
}

void DESC_MANAGER::GetUserCount(int& iTotal, int** paiEmpireUserCount, int& iLocalCount)
{
    *paiEmpireUserCount = &m_aiEmpireUserCount[0];

    int iCount = P2P_MANAGER::instance().GetCount();

    if (iCount < 0)
    {
        sys_err("P2P_MANAGER::instance().GetCount() == -1");
    }

    iTotal = m_iLocalUserCount + iCount;
    iLocalCount = m_iLocalUserCount;
}

DWORD DESC_MANAGER::MakeRandomKey(DWORD dwHandle)
{
    DWORD random_key = msl::random_int<uint32_t>();
    m_map_handle_random_key.emplace(dwHandle, random_key);
    return random_key;
}

bool DESC_MANAGER::GetRandomKey(DWORD dwHandle, DWORD* prandom_key)
{
    DESC_HANDLE_RANDOM_KEY_MAP::iterator it = m_map_handle_random_key.find(dwHandle);

    if (it == m_map_handle_random_key.end())
    {
        return false;
    }

    *prandom_key = it->second;
    return true;
}

LPDESC DESC_MANAGER::FindByLoginKey(DWORD dwKey)
{
    std::map<DWORD, CLoginKey*>::iterator it = m_map_pkLoginKey.find(dwKey);

    if (it == m_map_pkLoginKey.end())
    {
        return NULL;
    }

    return it->second->m_pkDesc;
}

DWORD DESC_MANAGER::CreateLoginKey(LPDESC d)
{
    DWORD dwKey = 0;

    do
    {
        dwKey = number(1, INT_MAX);

        if (m_map_pkLoginKey.find(dwKey) != m_map_pkLoginKey.end())
        {
            continue;
        }

        CLoginKey* pkKey = M2_NEW CLoginKey(dwKey, d);
        d->SetLoginKey(pkKey);
        m_map_pkLoginKey.emplace(dwKey, pkKey);
        break;
    } while (1);

    return dwKey;
}

void DESC_MANAGER::ProcessExpiredLoginKey()
{
    DWORD dwCurrentTime = get_dword_time();

    std::map<DWORD, CLoginKey*>::iterator it, it2;

    it = m_map_pkLoginKey.begin();

    while (it != m_map_pkLoginKey.end())
    {
        it2 = it++;

        if (it2->second->m_dwExpireTime == 0)
        {
            continue;
        }

        if (dwCurrentTime - it2->second->m_dwExpireTime > 60000)
        {
            M2_DELETE(it2->second);
            m_map_pkLoginKey.erase(it2);
        }
    }
}


input.cpp:
Genişlet Daralt Kopyala
#include "stdafx.h"
#include <sstream>

#include "desc.h"
#include "desc_manager.h"
#include "char.h"
#include "buffer_manager.h"
#include "config.h"
#include "profiler.h"
#include "p2p.h"
#include "log.h"
#include "db.h"
#include "questmanager.h"
#include "desc_client.h"
#include "fishing.h"
#include "priv_manager.h"
#include "../../common/CommonDefines.h"
#include "utils.h"


#ifdef ENABLE_ADVANCED_FLOOD_PROTECTION
#include <mutex>
#include <chrono>
#include <unordered_map>
#include <unordered_set>
#include <string>

extern void BanIP(const std::string& ip);
extern bool IsIPBanned(const std::string& ip);

static std::mutex s_floodMutex;
static std::unordered_map<int, std::pair<int, std::chrono::steady_clock::time_point>> s_headerFloodTracker;

int socket = lpDesc->GetSocket();
std::string ip = lpDesc->GetHostName();
auto now = std::chrono::steady_clock::now();

if (IsIPBanned(ip)) {
    sys_err("BLOCKED CONNECTION: Banned IP %s tried to connect", ip.c_str());
    lpDesc->SetPhase(PHASE_CLOSE);
    return true;
}

// Flood tracking
auto& rec = s_headerFloodTracker[socket];
if (std::chrono::duration_cast<std::chrono::seconds>(now - rec.second).count() > 1) {
    rec.first = 0;
    rec.second = now;
}
rec.first++;

if (rec.first > 100) {
    sys_err("FLOOD ATTACK: Banning IP %s for excessive packets", ip.c_str());
    lpDesc->SetPhase(PHASE_CLOSE);
    BanIP(ip);
    return true;
}
#endif


bool IsEmptyAdminPage()
{
    return g_stAdminPageIP.empty();
}

bool IsAdminPage(const char* ip)
{
    for (size_t n = 0; n < g_stAdminPageIP.size(); ++n)
    {
        if (g_stAdminPageIP[n] == ip)
        {
            return 1;
        }
    }

    return 0;
}

void ClearAdminPages()
{
    for (size_t n = 0; n < g_stAdminPageIP.size(); ++n)
    {
        g_stAdminPageIP[n].clear();
    }

    g_stAdminPageIP.clear();
}

CInputProcessor::CInputProcessor() : m_pPacketInfo(NULL), m_iBufferLeft(0)
{
    if (!m_pPacketInfo)
    {
        BindPacketInfo(&m_packetInfoCG);
    }
}

void CInputProcessor::BindPacketInfo(CPacketInfo* pPacketInfo)
{
    m_pPacketInfo = pPacketInfo;
}

bool CInputProcessor::Process(LPDESC lpDesc, const void* c_pvOrig, int iBytes, int& r_iBytesProceed)
{
    const char* c_pData = (const char*)c_pvOrig;

    BYTE    bLastHeader = 0;
    int        iLastPacketLen = 0;
    int        iPacketLen;

    if (!m_pPacketInfo)
    {
        sys_err("No packet info has been binded to");
        return true;
    }


#ifdef ENABLE_ADVANCED_FLOOD_PROTECTION
#include <mutex>
#include <chrono>
#include <unordered_map>
#include <unordered_set>
#include <string>

extern void BanIP(const std::string& ip);
extern bool IsIPBanned(const std::string& ip);

static std::mutex s_floodMutex;
static std::unordered_map<int, std::pair<int, std::chrono::steady_clock::time_point>> s_headerFloodTracker;

int socket = lpDesc->GetSocket();
std::string ip = lpDesc->GetHostName();
auto now = std::chrono::steady_clock::now();

if (IsIPBanned(ip)) {
    sys_err("BLOCKED CONNECTION: Banned IP %s tried to connect", ip.c_str());
    lpDesc->SetPhase(PHASE_CLOSE);
    return true;
}

// Flood tracking
auto& rec = s_headerFloodTracker[socket];
if (std::chrono::duration_cast<std::chrono::seconds>(now - rec.second).count() > 1) {
    rec.first = 0;
    rec.second = now;
}
rec.first++;

if (rec.first > 100) {
    sys_err("FLOOD ATTACK: Banning IP %s for excessive packets", ip.c_str());
    lpDesc->SetPhase(PHASE_CLOSE);
    BanIP(ip);
    return true;
}
#endif


    for (m_iBufferLeft = iBytes; m_iBufferLeft > 0;)
    {
        BYTE bHeader = (BYTE) * (c_pData);
        const char* c_pszName;

        if (bHeader == 0)
        {
            iPacketLen = 1;
        }

        else if (!m_pPacketInfo->Get(bHeader, &iPacketLen, &c_pszName))
        {
            sys_err("UNKNOWN HEADER: %d, LAST HEADER: %d(%d), REMAIN BYTES: %d, fd: %d",
                bHeader, bLastHeader, iLastPacketLen, m_iBufferLeft, lpDesc->GetSocket());
            //printdata((BYTE *) c_pvOrig, m_iBufferLeft);
            lpDesc->SetPhase(PHASE_CLOSE);
            return true;
        }

        if (m_iBufferLeft < iPacketLen)
        {
            return true;
        }

        if (bHeader)
        {
            if (test_server && bHeader != HEADER_CG_MOVE)
            {
                sys_log(0, "Packet Analyze [Header %d][bufferLeft %d] ", bHeader, m_iBufferLeft);
            }

            m_pPacketInfo->Start();

            int iExtraPacketSize = Analyze(lpDesc, bHeader, c_pData);

            if (iExtraPacketSize < 0)
            {
                return true;
            }

            iPacketLen += iExtraPacketSize;
            lpDesc->Log("%s %d", c_pszName, iPacketLen);
            m_pPacketInfo->End();
        }

#ifdef ENABLE_SEQUENCE_SYSTEM

        if (bHeader == HEADER_CG_PONG)
        {
            sys_log(0, "PONG! %u %u", m_pPacketInfo->IsSequence(bHeader), *(BYTE*)(c_pData + iPacketLen - sizeof(BYTE)));
        }

        if (m_pPacketInfo->IsSequence(bHeader))
        {
            BYTE bSeq = lpDesc->GetSequence();
            BYTE bSeqReceived = *(BYTE*)(c_pData + iPacketLen - sizeof(BYTE));

            if (bSeq != bSeqReceived)
            {
                sys_err("SEQUENCE %x mismatch 0x%x != 0x%x header %u", get_pointer(lpDesc), bSeq, bSeqReceived, bHeader);

                LPCHARACTER    ch = lpDesc->GetCharacter();

                char buf[1024];
                int    offset, len;

                offset = snprintf(buf, sizeof(buf), "SEQUENCE_LOG [%s]-------------\n", ch ? ch->GetName() : "UNKNOWN");

                if (offset < 0 || offset >= (int)sizeof(buf))
                {
                    offset = sizeof(buf) - 1;
                }

                for (size_t i = 0; i < lpDesc->m_seq_vector.size(); ++i)
                {
                    len = snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n",
                        lpDesc->m_seq_vector[i].hdr,
                        lpDesc->m_seq_vector[i].seq);

                    if (len < 0 || len >= (int)sizeof(buf) - offset)
                    {
                        offset += (sizeof(buf) - offset) - 1;
                    }

                    else
                    {
                        offset += len;
                    }
                }

                snprintf(buf + offset, sizeof(buf) - offset, "\t[%03d : 0x%x]\n", bHeader, bSeq);
                sys_err("%s", buf);

                lpDesc->SetPhase(PHASE_CLOSE);
                return true;
            }

            else
            {
                lpDesc->push_seq(bHeader, bSeq);
                lpDesc->SetNextSequence();
                //sys_err("SEQUENCE %x match %u next %u header %u", lpDesc, bSeq, lpDesc->GetSequence(), bHeader);
            }
        }

#endif

        c_pData += iPacketLen;
        m_iBufferLeft -= iPacketLen;
        r_iBytesProceed += iPacketLen;

        iLastPacketLen = iPacketLen;
        bLastHeader = bHeader;

        if (GetType() != lpDesc->GetInputProcessor()->GetType())
        {
            return false;
        }
    }

    return true;
}

void CInputProcessor::Pong(LPDESC d)
{
    d->SetPong(true);
}

void CInputProcessor::Handshake(LPDESC d, const char* c_pData)
{
    TPacketCGHandshake* p = (TPacketCGHandshake*)c_pData;

    if (d->GetHandshake() != p->dwHandshake)
    {
        sys_err("Invalid Handshake on %d", d->GetSocket());
        d->SetPhase(PHASE_CLOSE);
    }

    else
    {
        if (d->IsPhase(PHASE_HANDSHAKE))
        {
            if (d->HandshakeProcess(p->dwTime, p->lDelta, false))
            {
#ifdef _IMPROVED_PACKET_ENCRYPTION_
                d->SendKeyAgreement();
#else

                if (g_bAuthServer)
                {
                    d->SetPhase(PHASE_AUTH);
                }

                else
                {
                    d->SetPhase(PHASE_LOGIN);
                }

#endif // #ifdef _IMPROVED_PACKET_ENCRYPTION_
            }
        }

        else
        {
            d->HandshakeProcess(p->dwTime, p->lDelta, true);
        }
    }
}

void CInputProcessor::Version(LPCHARACTER ch, const char* c_pData)
{
    if (!ch)
    {
        return;
    }

    TPacketCGClientVersion2* p = (TPacketCGClientVersion2*)c_pData;
    sys_log(0, "VERSION: %s %s %s", ch->GetName(), p->timestamp, p->filename);
    ch->GetDesc()->SetClientVersion(p->timestamp);
}

void LoginFailure(LPDESC d, const char* c_pszStatus)
{
    if (!d)
    {
        return;
    }

    TPacketGCLoginFailure failurePacket;

    failurePacket.header = HEADER_GC_LOGIN_FAILURE;
    strlcpy(failurePacket.szStatus, c_pszStatus, sizeof(failurePacket.szStatus));

    d->Packet(&failurePacket, sizeof(failurePacket));
}

CInputHandshake::CInputHandshake()
{
    CPacketInfoCG* pkPacketInfo = M2_NEW CPacketInfoCG;
#ifdef ENABLE_SEQUENCE_SYSTEM
    pkPacketInfo->SetSequence(HEADER_CG_PONG, false);
#endif
    m_pMainPacketInfo = m_pPacketInfo;
    BindPacketInfo(pkPacketInfo);
}

CInputHandshake::~CInputHandshake()
{
    if (NULL != m_pPacketInfo)
    {
        M2_DELETE(m_pPacketInfo);
        m_pPacketInfo = NULL;
    }
}

std::vector<TPlayerTable> g_vec_save;

// BLOCK_CHAT
ACMD(do_block_chat);
// END_OF_BLOCK_CHAT

int CInputHandshake::Analyze(LPDESC d, BYTE bHeader, const char* c_pData)
{
    if (bHeader == 10)
    {
        return 0;
    }

    if (bHeader == HEADER_CG_TEXT)
    {
#ifdef ENABLE_PORT_SECURITY

        if (IsEmptyAdminPage() || !IsAdminPage(inet_ntoa(d->GetAddr().sin_addr))) // block if adminpage is not set or if not admin
        {
            sys_log(0, "SOCKET_CMD: BLOCK FROM(%s)", d->GetHostName());
            d->SetPhase(PHASE_CLOSE);
            return 0;
        }

#endif
        ++c_pData;
        const char* c_pSep;

        if (!(c_pSep = strchr(c_pData, '\n')))
        {
            d->SetPhase(PHASE_CLOSE); // @fixme187 setphase+ret0
            return 0;
        }

        if (*(c_pSep - 1) == '\r')
        {
            --c_pSep;
        }

        std::string stResult;
        std::string stBuf;
        stBuf.assign(c_pData, 0, c_pSep - c_pData);

        sys_log(0, "SOCKET_CMD: FROM(%s) CMD(%s)", d->GetHostName(), stBuf.c_str());

        if (!stBuf.compare("IS_SERVER_UP"))
        {
            if (g_bNoMoreClient)
            {
                stResult = "NO";
            }

            else
            {
                stResult = "YES";
            }
        }

        else if (stBuf == g_stAdminPagePassword)
        {
            if (!IsEmptyAdminPage())
            {
                if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr)))
                {
                    char szTmp[64];
                    snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr));
                    stResult += szTmp;
                }

                else
                {
                    d->SetAdminMode();
                    stResult = "UNKNOWN";
                }
            }

            else
            {
                d->SetAdminMode();
                stResult = "UNKNOWN";
            }
        }

        else if (!stBuf.compare("USER_COUNT"))
        {
            char szTmp[64];

            if (!IsEmptyAdminPage())
            {
                if (!IsAdminPage(inet_ntoa(d->GetAddr().sin_addr)))
                {
                    snprintf(szTmp, sizeof(szTmp), "WEBADMIN : Wrong Connector : %s", inet_ntoa(d->GetAddr().sin_addr));
                }

                else
                {
                    int iTotal;
                    int* paiEmpireUserCount;
                    int iLocal;
                    DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
                    snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal);
                }
            }

            else
            {
                int iTotal;
                int* paiEmpireUserCount;
                int iLocal;
                DESC_MANAGER::instance().GetUserCount(iTotal, &paiEmpireUserCount, iLocal);
                snprintf(szTmp, sizeof(szTmp), "%d %d %d %d %d", iTotal, paiEmpireUserCount[1], paiEmpireUserCount[2], paiEmpireUserCount[3], iLocal);
            }

            stResult += szTmp;
        }

        else if (!stBuf.compare("CHECK_P2P_CONNECTIONS"))
        {
            std::ostringstream oss(std::ostringstream::out);

            oss << "P2P CONNECTION NUMBER : " << P2P_MANAGER::instance().GetDescCount() << "\n";
            std::string hostNames;
            P2P_MANAGER::Instance().GetP2PHostNames(hostNames);
            oss << hostNames;
            stResult = oss.str();
            TPacketGGCheckAwakeness packet;
            packet.bHeader = HEADER_GG_CHECK_AWAKENESS;

            P2P_MANAGER::instance().Send(&packet, sizeof(packet));
        }

        else if (!stBuf.compare("PACKET_INFO"))
        {
            m_pMainPacketInfo->Log("packet_info.txt");
            stResult = "OK";
        }

        else if (!stBuf.compare("PROFILE"))
        {
            CProfiler::instance().Log("profile.txt");
            stResult = "OK";
        }

        //gift notify delete command
        else if (!stBuf.compare(0, 15, "DELETE_AWARDID "))
        {
            char szTmp[64];
            std::string msg = stBuf.substr(15, 26);

            TPacketDeleteAwardID p;
            p.dwID = (DWORD)(atoi(msg.c_str()));
            snprintf(szTmp, sizeof(szTmp), "Sent to DB cache to delete ItemAward, id: %d", p.dwID);
            //sys_log(0,"%d",p.dwID);
            // strlcpy(p.login, msg.c_str(), sizeof(p.login));
            db_clientdesc->DBPacket(HEADER_GD_DELETE_AWARDID, 0, &p, sizeof(p));
            stResult += szTmp;
        }

        else
        {
            stResult = "UNKNOWN";

            if (d->IsAdminMode())
            {
                if (!stBuf.compare(0, 7, "NOTICE "))
                {
                    std::string msg = stBuf.substr(7, 50);
                    LogManager::instance().CharLog(0, 0, 0, 1, "NOTICE", msg.c_str(), d->GetHostName());
                    BroadcastNotice(msg.c_str());
                }

#ifdef ENABLE_FULL_NOTICE

                else if (!stBuf.compare(0, 11, "BIG_NOTICE "))
                {
                    std::string msg = stBuf.substr(11, 50);
                    LogManager::instance().CharLog(0, 0, 0, 1, "BIG_NOTICE", msg.c_str(), d->GetHostName());
                    BroadcastNotice(msg.c_str(), true);
                }

#endif

                else if (!stBuf.compare("SHUTDOWN"))
                {
                    LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName());
                    TPacketGGShutdown p;
                    p.bHeader = HEADER_GG_SHUTDOWN;
                    P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShutdown));
                    sys_err("Accept shutdown command from %s.", d->GetHostName());
                    Shutdown(10);
                }

                else if (!stBuf.compare("SHUTDOWN_ONLY"))
                {
                    LogManager::instance().CharLog(0, 0, 0, 2, "SHUTDOWN", "", d->GetHostName());
                    sys_err("Accept shutdown only command from %s.", d->GetHostName());
                    Shutdown(10);
                }

                else if (!stBuf.compare(0, 3, "DC "))
                {
                    std::string msg = stBuf.substr(3, LOGIN_MAX_LEN);

                    TPacketGGDisconnect pgg;

                    pgg.bHeader = HEADER_GG_DISCONNECT;
                    strlcpy(pgg.szLogin, msg.c_str(), sizeof(pgg.szLogin));

                    P2P_MANAGER::instance().Send(&pgg, sizeof(TPacketGGDisconnect));
                    DESC_MANAGER::instance().DestroyLoginKey(msg);
                }

                else if (!stBuf.compare(0, 10, "RELOAD_CRC"))
                {
                    LoadValidCRCList();

                    BYTE bHeader = HEADER_GG_RELOAD_CRC_LIST;
                    P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE));
                    stResult = "OK";
                }

                else if (!stBuf.compare(0, 20, "CHECK_CLIENT_VERSION"))
                {
                    CheckClientVersion();

                    BYTE bHeader = HEADER_GG_CHECK_CLIENT_VERSION;
                    P2P_MANAGER::instance().Send(&bHeader, sizeof(BYTE));
                    stResult = "OK";
                }

                else if (!stBuf.compare(0, 6, "RELOAD"))
                {
                    if (stBuf.size() == 6)
                    {
                        LoadStateUserCount();
                        db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0);
                    }

                    else
                    {
                        char c = stBuf[7];

                        switch (LOWER(c))
                        {
                        case 'u':
                            LoadStateUserCount();
                            break;

                        case 'p':
                            db_clientdesc->DBPacket(HEADER_GD_RELOAD_PROTO, 0, NULL, 0);
                            break;

                        case 'q':
                            quest::CQuestManager::instance().Reload();
                            break;

                        case 'f':
                            fishing::Initialize();
                            break;

                        case 'a':
                            db_clientdesc->DBPacket(HEADER_GD_RELOAD_ADMIN, 0, NULL, 0);
                            sys_log(0, "Reloading admin infomation.");
                            break;
                        }
                    }
                }

                else if (!stBuf.compare(0, 6, "EVENT "))
                {
                    std::istringstream is(stBuf);
                    std::string strEvent, strFlagName;
                    long lValue;
                    is >> strEvent >> strFlagName >> lValue;

                    if (!is.fail())
                    {
                        sys_log(0, "EXTERNAL EVENT FLAG name %s value %d", strFlagName.c_str(), lValue);
                        quest::CQuestManager::instance().RequestSetEventFlag(strFlagName, lValue);
                        stResult = "EVENT FLAG CHANGE ";
                        stResult += strFlagName;
                    }

                    else
                    {
                        stResult = "EVENT FLAG FAIL";
                    }
                }

                // BLOCK_CHAT
                else if (!stBuf.compare(0, 11, "BLOCK_CHAT "))
                {
                    std::istringstream is(stBuf);
                    std::string strBlockChat, strCharName;
                    long lDuration;
                    is >> strBlockChat >> strCharName >> lDuration;

                    if (!is.fail())
                    {
                        sys_log(0, "EXTERNAL BLOCK_CHAT name %s duration %d", strCharName.c_str(), lDuration);

                        do_block_chat(NULL, const_cast<char*> (stBuf.c_str() + 11), 0, 0);

                        stResult = "BLOCK_CHAT ";
                        stResult += strCharName;
                    }

                    else
                    {
                        stResult = "BLOCK_CHAT FAIL";
                    }
                }

                // END_OF_BLOCK_CHAT
                else if (!stBuf.compare(0, 12, "PRIV_EMPIRE "))
                {
                    int    empire, type, value, duration;
                    std::istringstream is(stBuf);
                    std::string strPrivEmpire;
                    is >> strPrivEmpire >> empire >> type >> value >> duration;

                    value = MINMAX(0, value, 1000);
                    stResult = "PRIV_EMPIRE FAIL";

                    if (!is.fail())
                    {
                        // check parameter
                        if (empire < 0 || 3 < empire);

                        else if (type < 1 || 4 < type);

                        else if (value < 0);

                        else if (duration < 0);

                        else
                        {
                            stResult = "PRIV_EMPIRE SUCCEED";

                            duration = duration * (60 * 60);

                            sys_log(0, "_give_empire_privileage(empire=%d, type=%d, value=%d, duration=%d) by web",
                                empire, type, value, duration);
                            CPrivManager::instance().RequestGiveEmpirePriv(empire, type, value, duration);
                        }
                    }
                }
            }
        }

        sys_log(1, "TEXT %s RESULT %s", stBuf.c_str(), stResult.c_str());
        stResult += "\n";
        d->Packet(stResult.c_str(), stResult.length());
        return (c_pSep - c_pData) + 1;
    }

    else if (bHeader == HEADER_CG_MARK_LOGIN)
    {
        if (!guild_mark_server)
        {
            sys_err("Guild Mark login requested but i'm not a mark server!");
            d->SetPhase(PHASE_CLOSE);
            return 0;
        }

        sys_log(0, "MARK_SERVER: Login");
        d->SetPhase(PHASE_LOGIN);
        return 0;
    }

    else if (bHeader == HEADER_CG_STATE_CHECKER)
    {
        if (d->isChannelStatusRequested())
        {
            return 0;
        }

        d->SetChannelStatusRequested(true);
        db_clientdesc->DBPacket(HEADER_GD_REQUEST_CHANNELSTATUS, d->GetHandle(), NULL, 0);
    }

    else if (bHeader == HEADER_CG_PONG)
    {
        Pong(d);
    }

    else if (bHeader == HEADER_CG_HANDSHAKE)
    {
        Handshake(d, c_pData);
    }

#ifdef _IMPROVED_PACKET_ENCRYPTION_

    else if (bHeader == HEADER_CG_KEY_AGREEMENT)
    {
        // Send out the key agreement completion packet first
        // to help client to enter encryption mode
        d->SendKeyAgreementCompleted();
        // Flush socket output before going encrypted
        d->ProcessOutput();

        TPacketKeyAgreement* p = (TPacketKeyAgreement*)c_pData;

        if (!d->IsCipherPrepared())
        {
            sys_err("Cipher isn't prepared. %s maybe a Hacker.", inet_ntoa(d->GetAddr().sin_addr));
            d->DelayedDisconnect(5);
            return 0;
        }

        if (d->FinishHandshake(p->wAgreedLength, p->data, p->wDataLength))
        {
            // Handshaking succeeded
            if (g_bAuthServer)
            {
                d->SetPhase(PHASE_AUTH);
            }

            else
            {
                d->SetPhase(PHASE_LOGIN);
            }
        }

        else
        {
            sys_log(0, "[CInputHandshake] Key agreement failed: al=%u dl=%u",
                p->wAgreedLength, p->wDataLength);
            d->SetPhase(PHASE_CLOSE);
        }
    }

#endif // _IMPROVED_PACKET_ENCRYPTION_

    else
    {
        sys_err("Handshake phase does not handle packet %d (fd %d) from %s:%u", bHeader, d->GetSocket(), d->GetHostName(), d->GetPort());    //@warme016 host and port
    }

    return 0;
}

Dipnot:
Saldırgan bir IP adresinden 1 saniyede 100’den fazla veri/paket gönderirse:
Anında kalıcı olarak banlanır.
Aynı IP bir daha sunucuya hiç bağlanamaz, bağlantı kurma aşamasında engellenir.
Bu IP’ler unordered_set içinde tutulur ve bağlantı kurulurken kontrol edilir.


Banlanan IP, sunucuya yeni bir bağlantı göndermeye kalksa bile:



Böylece kanal kapanmaz saldırganın sistemi yavaşlatmasına izin verilmez:
Genişlet Daralt Kopyala
if (IsIPBanned(ip)) {
    lpDesc->SetPhase(PHASE_CLOSE); // Bağlantı anında kesilir
    return;
}

Tüm IP ban işlemleri std::mutex ile korunur.
Yani sistem, eşzamanlı binlerce bağlantı olsa bile hatalı banlama veya çakışma yapmaz.
Ama tek bir problemimiz var :D Reboot atığımızda Banlı IP’ler Unutuluyor :D .txt mantığına geçeceğim umarım :D
json'da olabilir

JSON:
Genişlet Daralt Kopyala
{
  "banned_ips": {
    "192.168.1.1": "permanent",
    "203.0.113.5": "2025-06-11T01:30:00"
  }
}



Aktif oyunlardan dönüşler gelse olabildiğince stabil bir yapı kuracağım ama :D maalesef
 
Son düzenleme:
Geri
Üst