/* * CSB Connect Flood Guard * Copyright (C) 2026 counter-strike-boost.com * * Rate-limits connections per IP using a sliding window kept in Tries. An IP * that reconnects too many times inside the window is temporarily blocked, * mitigating connect-flood and reconnect spam without touching real players. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. It is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See for details. */ #include new const PLUGIN[] = "CSB Connect Flood Guard" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pEnabled, g_pMaxConn, g_pWindow, g_pBanTime new Trie:g_tFirst // ip -> first-seen systime for the current window new Trie:g_tCount // ip -> connections seen in the current window new Trie:g_tBlock // ip -> block-until systime public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_flood_enabled", "1") g_pMaxConn = register_cvar("csb_flood_maxconn", "5") g_pWindow = register_cvar("csb_flood_window", "10") g_pBanTime = register_cvar("csb_flood_bantime", "60") g_tFirst = TrieCreate() g_tCount = TrieCreate() g_tBlock = TrieCreate() } public plugin_end() { TrieDestroy(g_tFirst) TrieDestroy(g_tCount) TrieDestroy(g_tBlock) } public client_connect(id) { if (!get_pcvar_num(g_pEnabled)) return new ip[24] get_user_ip(id, ip, charsmax(ip), 1) if (!ip[0]) return new now = get_systime() // still inside an active block? new until if (TrieGetCell(g_tBlock, ip, until)) { if (now < until) { kickIp(id, "connecting too fast, try again shortly") return } TrieDeleteKey(g_tBlock, ip) } new first, count if (!TrieGetCell(g_tFirst, ip, first)) { TrieSetCell(g_tFirst, ip, now) TrieSetCell(g_tCount, ip, 1) return } new window = get_pcvar_num(g_pWindow) // window elapsed -> start a fresh one if (now - first > window) { TrieSetCell(g_tFirst, ip, now) TrieSetCell(g_tCount, ip, 1) return } TrieGetCell(g_tCount, ip, count) count++ TrieSetCell(g_tCount, ip, count) if (count > get_pcvar_num(g_pMaxConn)) { new banTime = get_pcvar_num(g_pBanTime) TrieSetCell(g_tBlock, ip, now + banTime) log_amx("[CSB Flood] %s made %d connects in %ds - blocked for %ds", ip, count, window, banTime) kickIp(id, "connect flood protection") } } kickIp(id, const reason[]) { server_cmd("kick #%d ^"CSB: %s^"", get_user_userid(id), reason) server_exec() }