Защита Garry's-Mod-сервера от DDoS-атак

Опубликовано 23 мин. чтения

В Garry's Mod игровой трафик и серверный запрос идут через один и тот же порт 27015. Какие правила на сервере действительно работают, как защитить RCON и сетевые события Lua, и с какого объёма атаки помогает только фильтрация в сети перед сервером.

Garry's-Mod-сервер, который в восемь вечера на три минуты пропадает и потом возвращается, редко страдает от железа. В подавляющем большинстве случаев идёт атака, причём ровно в те часы, когда подключено больше всего игроков. Поэтому защита Garry's Mod от DDoS начинается с одного: нужно знать, какие пакеты вообще вправе доходить до вашего сервера. В этой статье по порядку разобрано, что вы можете закрыть сами в ближайшие десять минут и без единого цента, где эти меры упираются в физику, и что после этого должно происходить в сети перед сервером.

Все указания относятся к серверу srcds под Debian 12, Debian 13, Ubuntu 22.04 LTS или Ubuntu 24.04 LTS. Конфигурационный файл лежит по пути garrysmod/cfg/server.cfg, команды написаны для root, если вы работаете под обычным пользователем, добавляйте перед каждой командой sudo. Речь всегда идёт о работе на собственном root-сервере или выделенном сервере, а не о слоте у хостера игровых серверов.

Если атака идёт прямо сейчас: ничего не меняйте в server.cfg и не перезапускайте srcds. Сначала сохраните измерения (раздел 9), после атаки их уже не будет. Перезапуск обнулит счётчики и вернёт сервер в тот же самый поток.

Почему Garry's-Mod-серверу нужна защита от DDoS

Garry's-Mod-сервер публикует свой IP-адрес и порт сам. Это не недосмотр, а условие работы: тот, кого нет в браузере серверов, не получит новых игроков. Запись появляется потому, что сервер регистрируется на мастер-сервере Steam и после этого отвечает на любой A2S-запрос, пришедший снаружи. Значит, вопрос никогда не стоит так, найдёт ли атакующий ваш адрес. Вопрос только в том, что произойдёт, когда он по нему ударит.

К этому добавляется характер сообществ. В Garry's Mod играют преимущественно не раундами, а в постоянных мирах: DarkRP-сообщество месяцами ведёт в базе данных учётные записи игроков, их имущество, работу и прогресс. Поэтому сбой в пятницу вечером стоит дороже проигранного матча, он стоит постоянных игроков. Именно поэтому три самые частые причины атак — это конкурирующие сообщества, забаненные игроки и купленные server booter, то есть сервисы, которые за несколько евро в месяц запускают атаку на произвольный адрес. Ни навыков, ни заметных денег атакующему для этого не нужно.

Технически сходятся три особенности. Игровой трафик идёт по UDP, а в UDP нет установления соединения, которого можно было бы потребовать: адрес отправителя легко подделать. Серверный запрос занимает тот же порт, что и игра, поэтому грубая блокировка всегда бьёт по обоим сразу. И надо всем этим стоит Lua: каждый аддон из Workshop приносит собственный код в тот же процесс, и одного незащищённого сетевого события хватает, чтобы единственный клиент затормозил сервер вообще без какой-либо полосы пропускания. Что такое DDoS-атака по существу, объясняет статья Что такое DDoS-атака?.

Порты, о которых в Garry's Mod на самом деле идёт речь

Garry's-Mod-сервер по умолчанию запускается на порту 27015: на UDP для игры вместе с серверным запросом и на TCP для RCON. Номер меняется при запуске параметром -port, при нескольких экземплярах его увеличивают (27016, 27017 и так далее). Типичная строка запуска выглядит так:

./srcds_run -game garrysmod -console \
  -port 27015 \
  +maxplayers 64 \
  +gamemode darkrp \
  +map rp_downtown_v4c_v2 \
  +sv_setsteamaccount ВАШ_GSLT_ТОКЕН \
  +host_workshop_collection 123456789 \
  -authkey ВАШ_КЛЮЧ_STEAM_WEB_API

Отсюда и складывается вся поверхность атаки. Таблица ниже — основа для каждого правила файрвола в следующих разделах:

Порт и протокол Для чего Меняется через Место в открытой сети
27015/UDP Игровой трафик и A2S-запрос на одном и том же порту -port да, это единственный порт, который действительно должен быть открыт
27015/TCP RCON, протокол Source RCON -port (тот же номер, что и у игры) нет, только для вашего собственного адреса
27005/UDP Клиентский порт, открывается со стороны игрока -clientport нет, правило на сервере не требуется
27020/UDP SourceTV +tv_port только если вы действительно ведёте трансляцию
26901/UDP Регистрация на мастер-сервере Steam исходящий нет, входящее правило не требуется
80/TCP и 443/TCP FastDL через sv_downloadurl, если веб-сервер стоит на том же хосте веб-сервер только если FastDL лежит там (лучше разнести)
3306/TCP MySQL для DarkRP и данных игроков (через модуль mysqloo) bind-address нет, исключительно 127.0.0.1
22/TCP SSH-доступ sshd_config да, но с ограничением

Из этих восьми строк без ограничений в открытую сеть относится ровно одна: 27015/UDP. Всё остальное либо ограничивается вашим собственным адресом, либо привязывается к 127.0.0.1, либо вообще не запускается. Самая дорогая ошибка в этой теме — предположение, будто в Garry's Mod есть отдельный query-порт, который можно просто закрыть. Его нет.

Что вы можете сделать сами, прежде чем тратить деньги

Этот раздел самый длинный, и так задумано. Аккуратно настроенный Garry's-Mod-сервер выдерживает небольшие и средние атаки собственными силами, независимо от того, у какого провайдера он стоит. Ничто из перечисленного не стоит денег, и большая часть делается за четверть часа.

1. Инвентаризация: что вообще слушает сеть

Прежде чем написать хотя бы одно правило, посмотрите, что ваш сервер предлагает наружу. Не гадайте, а смотрите:

ss -lntup

Интерес представляет колонка с локальным адресом. 0.0.0.0:27015 и [::]:27015 означают «доступен из всего интернета», 127.0.0.1:3306 означает «только локально» и правила файрвола не требует. На DarkRP-сервере, который развивался постепенно, служб там почти всегда больше, чем вы ожидаете: MySQL, веб-сервер для FastDL, панель, Discord-бот, второй тестовый сервер на 27016 и давно забытая голосовая служба. Взгляд атакующего даёт скан портов снаружи:

nmap -Pn -sU -sT -p- --min-rate 1000 ВАШ.IP.АДРЕС.СЕРВЕРА

2. Оставьте открытыми только те порты, которые действительно нужны srcds

Для Garry's Mod наружу достаточно одного разрешающего правила, к нему добавляются SSH и ограниченный доступ к RCON. В UFW это выглядит так, причём именно в таком порядке, чтобы не закрыть доступ самому себе:

ufw allow 22/tcp comment 'SSH'
ufw allow 27015/udp comment 'Garrys Mod игровой порт и A2S'
ufw allow from 203.0.113.10 to any port 27015 proto tcp comment 'RCON'
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ufw status verbose

Замените 203.0.113.10 на свой собственный адрес. SourceTV на 27020/UDP открывайте только тогда, когда вы действительно ведёте трансляцию. Полная инструкция вместе с запасным путём есть в статье Настройка файрвола UFW без потери доступа. Если доступ всё же потерян: у KVM root-серверов и выделенных серверов KernelHost нет ни IPMI, ни iDRAC, и вернуться можно через VNC-консоль в личном кабинете. Она не зависит от сетевого стека гостевой системы, и правило файрвола внутри гостя её заблокировать не может.

База данных не должна попадать в открытую сеть ни при каких обстоятельствах. Проверьте в /etc/mysql/mariadb.conf.d/50-server.cnf, что там стоит:

bind-address = 127.0.0.1

3. Ограничьте A2S-запросы, не вылетев из списка серверов

Здесь кроется ошибка, которая дороже всего обходится большинству Garry's-Mod-серверов. Игровой трафик и серверный запрос занимают один и тот же порт, поэтому сплошная блокировка или слишком жёсткое ограничение интенсивности на 27015/UDP выбрасывает собственных игроков и доводит атаку до конца за атакующего. Правильная точка приложения сил — различать пакеты запросов и игровые пакеты.

Движок приносит для этого три консольные переменные, которые задаются в server.cfg. Их значения по умолчанию консервативны, но они всё же заданы:

sv_max_queries_sec 3
sv_max_queries_sec_global 60
sv_max_queries_window 30

sv_max_queries_sec ограничивает число обработанных запросов на один адрес отправителя (по умолчанию 3 в секунду), sv_max_queries_sec_global ставит потолок для суммы по всем адресам (по умолчанию 60 в секунду), sv_max_queries_window задаёт окно усреднения (по умолчанию 30 секунд). Эти значения берегут CPU от бессмысленной генерации ответов. Они не мешают самим пакетам доходить до сервера, а тот, кто затянет глобальное значение слишком туго, во время атаки пропадёт из браузера серверов, потому что без ответа останутся и запросы сайтов со списками серверов.

Уровнем ниже трафик запросов отделяется чисто. Все пакеты Source-движка без установленного соединения начинаются с четырёх выставленных байт (0xffffffff), а у трафика уже подключённых игроков такого заголовка нет. Именно на этот признак и вешается через nftables ограничение интенсивности по адресу источника:

table inet gmod {
    chain input {
        type filter hook input priority -10; policy accept;
        udp dport 27015 @th,64,32 0xffffffff \
            meter a2sflood { ip saddr limit rate over 8/second burst 20 packets } drop
    }
}

Файл загружается командой nft -f. Приоритет -10 обеспечивает срабатывание правила перед цепочкой фильтрации UFW, а @th,64,32 читает первые четыре байта за UDP-заголовком. В классическом iptables то же самое даёт сравнение через u32:

iptables -A INPUT -p udp --dport 27015 \
  -m u32 --u32 "0>>22&0x3C@8=0xFFFFFFFF" \
  -m hashlimit --hashlimit-name gmod_a2s --hashlimit-mode srcip \
  --hashlimit-above 8/sec --hashlimit-burst 20 -j DROP

Момент, который умалчивает почти любая инструкция в сети: без установленного соединения идёт не только серверный запрос, но и само подключение к серверу. Игрок, который заходит на сервер, отправляет несколько пакетов с тем же заголовком, прежде чем окажется в игре. Поэтому слишком узкий предел закрывает вход новым игрокам, хотя сервер остаётся доступным. Начинайте с запасом (от 8 до 15 пакетов в секунду на один адрес) и затягивайте порог только после того, как неделю померяете обычный режим работы.

4. Защитите RCON или отключите его совсем

На серверах Source RCON — излюбленная цель, и сразу по трём причинам. Во-первых, он висит на том же номере порта, что и игра, только на TCP, и находится без всякого поиска. Во-вторых, протокол Source RCON передаёт пароль открытым текстом, без TLS и без обмена ключами: у того, кто читает трафик, пароль есть. В-третьих, выигрыш максимальный, ведь у кого есть RCON, тот меняет карту, банит всех игроков, правит конфигурацию и останавливает сервер. Атакующему, который захватил RCON, полоса пропускания уже вообще не нужна.

Никогда не оставляйте rcon_password пустым и не придумывайте его на ходу, достаточно значения из openssl rand -base64 32. Против попыток подбора у движка есть собственный тормоз:

rcon_password "ЗДЕСЬ_ДЛИННЫЙ_СЛУЧАЙНЫЙ_ПАРОЛЬ"
sv_rcon_minfailures 3
sv_rcon_maxfailures 5
sv_rcon_minfailuretime 30
sv_rcon_banpenalty 1440

После трёх неудачных попыток за 30 секунд адрес блокируется на сутки. Два предупреждения к этому. Во-первых, ровно этот механизм заблокирует и вашу собственную админ-панель, если в ней сохранён старый пароль: то, о чём владельцы сообщают как «RCON внезапно перестал работать», чаще всего и есть своя же блокировка. Во-вторых, ограничение на файрволе из шага 2 всё равно действеннее, потому что оно не пропускает попытку до самого приложения. Тому, кому RCON нужен лишь изредка, стоит держать порт полностью закрытым и работать через проброс порта по SSH:

ssh -N -L 27015:127.0.0.1:27015 root@ВАШ.IP.АДРЕС.СЕРВЕРА

5. Ограничьте сетевые сообщения Lua: самый частый сбой по собственной вине

Заметная часть сбоев Garry's Mod, о которых сообщают как о DDoS, никаким DDoS не является. Это перегрузки Lua, которые вызывает один-единственный подключённый клиент со скоростью в несколько килобит в секунду. Причина в устройстве библиотеки net: как только аддон регистрирует сетевое событие через util.AddNetworkString и слушает его через net.Receive, любой клиент может запускать это событие в цикле. Без собственного ограничения сервер выполняет каждое отдельное сообщение. Facepunch многократно зафиксировала это в своих отчётах об ошибках и решения в движке не предусмотрела: ограничение — это прямая обязанность автора аддона.

Поэтому проверяйте каждый собственный и каждый купленный аддон на три вещи: верхний предел на одного игрока в секунду, проверку длины сообщения и то, что игрок определяется на стороне сервера из второго параметра, а не из содержимого сообщения. Рабочий образец выглядит так:

util.AddNetworkString("khrp_buy")

local budget = {}

net.Receive("khrp_buy", function(len, ply)
    if not IsValid(ply) then return end
    if len > 256 then return end

    local now = CurTime()
    local b = budget[ply]

    if not b or now - b.start >= 1 then
        b = { start = now, count = 0 }
        budget[ply] = b
    end

    b.count = b.count + 1
    if b.count > 10 then return end

    KHRP.HandleBuy(ply, net.ReadString())
end)

hook.Add("PlayerDisconnected", "khrp_budget_cleanup", function(ply)
    budget[ply] = nil
end)

К этому добавляются две строки в server.cfg. В Garry's Mod sv_allowcslua по умолчанию стоит на 1 и разрешает клиентам выполнять собственный код через lua_run_cl и lua_openscript_cl: на публичном сервере это значение должно быть 0. А sv_kickerrornum отключает клиентов, которые создают больше указанного числа клиентских ошибок (по умолчанию 0, то есть выключено):

sv_allowcslua 0
sv_kickerrornum 25

6. Разнесите содержимое Workshop и FastDL с игровым сервером

Аддоны из Workshop в Garry's Mod не побочная тема, а норма: DarkRP-сообщество подключает свою коллекцию через +host_workshop_collection, и клиенты загружают это содержимое напрямую из Steam. Ваш канал это не нагружает. Ключ из -authkey — это ключ Steam Web API, и обращаться с ним нужно как с паролем: ему место в стартовом скрипте, а не в публичном репозитории и не в Discord-канале.

Полосу пропускания съедает второй путь. Всё, что приходит не из Workshop (собственные карты, звуки, материалы), идёт по каналу загрузки. Без sv_downloadurl этот канал проходит через сам игровой порт и напрямую конкурирует с игровым трафиком. С FastDL он идёт по HTTP. Если этот веб-сервер стоит на том же хосте и том же IP-адресе, оба делят один канал: волна подключений или атака на 80/TCP бьёт тогда и по игре. Осмысленны такие значения:

sv_downloadurl "https://fastdl.example.com/garrysmod/"
sv_allowdownload 1
sv_allowupload 0
net_maxfilesize 64

sv_allowupload 0 лишает клиентов возможности отправлять на сервер собственные файлы и закрывает тем самым путь, который не нужен и никем не контролируется. net_maxfilesize ограничивает размер передаваемых по игровому каналу файлов в мегабайтах. По возможности вынесите FastDL на другой хост или хотя бы за отдельное имя, тогда нагрузка не ляжет на тот же адрес, что и игровой порт.

7. Перехватите флуд подключений и исчерпание слотов

Исчерпание слотов — это атака, которой не нужна полоса пропускания: атакующий занимает автоматическими подключениями все свободные места, и настоящие игроки видят полный сервер. В Garry's Mod дело осложняется тем, что каждое подключение стоит серверу работы, ведь список ресурсов и игровой режим согласуются задолго до того, как игрок окажется в игре.

Против этого работают четыре вещи. Первая — реалистичный верхний предел: задавать +maxplayers выше того, что выдерживает ваш игровой режим, значит только увеличивать поверхность атаки. Вторая — sv_timeout, который определяет, через сколько секунд без сообщения клиент отключается (в распространённых конфигурациях 120): тот, кто хочет быстрее избавляться от зависших полусоединений, ставит значение ниже. Третья — ограничение интенсивности пакетов без установленного соединения из шага 3, ведь подключение к серверу идёт именно через них. Четвёртая, для закрытых групп, — пароль на сервер:

sv_password "nasha_gruppa_2026"
sv_timeout 90
sv_filterban 1
sv_region 3

Настоящего белого списка в Garry's Mod нет, он появляется только через расширения вроде ULX или через собственную проверку в хуке CheckPassword. И одно нужно понимать чётко: белый список защищает вашу игровую логику, а не ваш канал. Атакующий, который заливает ваш сервер трафиком, подключаться вообще не собирается. Его пакеты будут отклонены, но прийти они всё равно успели, и в этом вся суть.

8. Разгрузите ядро: отслеживание соединений и буфер приёма

Этот шаг объясняет сбои, которые выглядят как объёмная атака, но ею не являются. Для UDP-трафика ядро заводит записи в таблице отслеживания соединений (conntrack), и при подделанных адресах отправителя каждый адрес означает новую запись. Когда таблица заполнена, ядро отбрасывает пакеты без разбора: вместе с атакой вылетают и ваши игроки, а в системном логе появляется «nf_conntrack: table full». Текущее значение и верхний предел показывает:

sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max

Действеннее всего вообще не отслеживать игровой трафик, ведь свои сессии движок ведёт сам:

table inet raw {
    chain prerouting {
        type filter hook prerouting priority raw; policy accept;
        udp dport { 27015, 27020 } notrack
    }
    chain output {
        type filter hook output priority raw; policy accept;
        udp sport { 27015, 27020 } notrack
    }
}

В iptables этому соответствует iptables -t raw -A PREROUTING -p udp --dport 27015 -j NOTRACK и та же строка для OUTPUT с --sport. После этого порту нужно явное разрешающее правило, потому что без отслеживания перестаёт работать любое правило, которое проверяет уже установленное состояние. Если к тому же пакеты приходят быстрее, чем srcds успевает их забирать, переполняется буфер приёма, и для игроков это выглядит как потеря пакетов при свободном канале:

net.core.rmem_max = 16777216
net.core.rmem_default = 1048576
net.core.netdev_max_backlog = 16384

Эти строки помещают в отдельный файл в /etc/sysctl.d/ и применяют командой sysctl --system. Нужны ли они вообще, подскажет само ядро: если UdpRcvbufErrors в выводе nstat -az растёт, они пригодятся. Если счётчик стоит на нуле, настройка ничего не изменит. Это запас прочности, а не защита.

9. Сохраняйте измерения, пока всё работает нормально

Самый важный шаг — тот, который почти никто не делает заранее: собрать базу для сравнения. Без нормального значения вы после инцидента не скажете, много ли это, 40 000 пакетов в секунду, или это просто субботний вечер. Посчитайте нормальное значение для своего сервера один раз: 64 игрока с cl_cmdrate 66 создают около 4200 входящих пакетов в секунду, и всё, что заметно выше, требует объяснения. С apt-get install -y vnstat sysstat измерение идёт постоянно в фоне. Во время инцидента хватает четырёх команд:

sar -n DEV 1 10
ip -s link show eth0
nstat -az | grep -i udp
tcpdump -ni eth0 -c 200 "udp port 27015 and udp[8:4] = 0xffffffff"

Первая показывает пакеты и байты в секунду, вторая счётчики отброшенных пакетов на интерфейсе, третья счётчики ошибок UDP в ядре. Четвёртая строка показывает исключительно пакеты без установленного соединения, то есть ровно тот класс, которым злоупотребляет поток запросов: если счётчик набирается за секунды, а подключённых почти нет, ответ у вас есть. Всегда ограничивайте tcpdump через -c, ведь захват трафика под полной нагрузкой дополнительно нагружает и без того перегруженный сервер. Как разобрать полученные значения, описано в статье Как определить DDoS-атаку на сервере.

Что такое уязвимость A2S-reflection и касается ли она меня до сих пор

A2S-reflection — это атака, в которой ваш сервер не цель, а инструмент. Атакующий отправляет небольшой запрос с подделанным адресом отправителя на тысячи игровых серверов, и их заметно бо́льшие ответы сходятся у настоящей жертвы. Исторически запрос A2S_INFO занимал 25 байт (4 байта 0xFFFFFFFF, 1 байт 0x54 и ещё 20 байт на строку «Source Engine Query»), а ответ на него несколько сотен байт. US-CERT ведёт протокол Steam в своём списке атак с усилением с коэффициентом 5,5, а это значит: один гигабит у атакующего превращается в 5,5 гигабита у жертвы.

Valve закрыла эту брешь начиная с ноября 2020 года, причём двумя путями. Пакеты запросов без установленного соединения с тех пор должны дополняться отправителем до 1200 байт, отчего запрос становится больше ответа, а коэффициент усиления падает ниже 1. На время перехода владельцы серверов могли заранее включить более строгое поведение переменной окружения STEAM_GAMESERVER_MIN_CONNECTIONLESS_PACKET_SIZE=1200. Вдобавок на A2S_PLAYER и A2S_RULES сервер отвечает не сразу данными, а вызовом challenge (S2C_CHALLENGE), который спрашивающий должен вернуть вторым запросом. Тот, кто подделывает адрес отправителя, этот challenge никогда не увидит.

Для вас отсюда следуют две вещи. Держите бинарник сервера в актуальном состоянии, ведь защита заложена в подсистеме Steam-игрового-сервера, а не в вашей конфигурации. И не путайте reflection с потоком запросов против вас самих: против второй формы помогает исключительно ограничение интенсивности из шага 3, а сверх того фильтрация в сети перед сервером.

Где эти меры заканчиваются: полоса пропускания и интенсивность пакетов

Теперь та часть, которую не решит ни один конфигурационный файл. Всё описанное выше работает на вашем сервере, то есть в конце канала. Правило файрвола принимает решение о пакете, который уже прошёл по кабелю. Вы можете его отбросить, но не можете сделать неотправленным.

Давайте посчитаем. Типовой игровой сервер подключён на 1 Гбит/с, это 125 мегабайт в секунду, и канал заполнен, как только кто-то отправит больше. Вторая величина обычно бьёт раньше: при минимально возможном размере пакета в 64 байта в 1 Гбит/с помещается около 1,49 миллиона пакетов в секунду, а в 10 Гбит/с около 14,88 миллиона. Обычное серверное ядро в зависимости от CPU и сетевой карты обрабатывает несколько сотен тысяч из них, а дальше начинает отбрасывать. Значит, атака, которая не заполняет ваш канал даже на треть, всё равно способна положить сервер, потому что процессорное время уходит на само отбрасывание. Владельцы серверов описывают это словами «загрузка ведь была совсем не высокой, а лаги были у всех».

Показатель Значение
Запрос A2S_INFO, исторический размер 25 байт
Коэффициент усиления протокола Steam (US-CERT) 5,5
Минимальный размер пакетов запроса без установленного соединения с 2020 года 1200 байт
Обычный трафик: 64 игрока при cmdrate 66 около 4200 входящих пакетов в секунду
1 Гбит/с при пакетах размером 64 байта около 1,49 миллиона пакетов в секунду (125 мегабайт в секунду)
10 Гбит/с при пакетах размером 64 байта около 14,88 миллиона пакетов в секунду
Типовой размер атаки против игрового сервера сообщества от 5 до 50 Гбит/с
Пик, измеренный на серверах KernelHost 473,4 Гбит/с при 41,5 миллиона пакетов в секунду

Чтобы понимать, какие порядки величин встречаются на практике: на серверах KernelHost были отфильтрованы, среди прочего, UDP-флуд мощностью более 112,2 Гбит/с при более чем 8,7 миллиона пакетов в секунду по игровому серверу, а также многовекторная атака мощностью более 473,4 Гбит/с при более чем 41,5 миллиона пакетов в секунду по голосовому серверу. 473,4 Гбит/с — это примерно в 470 раз больше подключения на 1 Гбит/с и всё ещё примерно в 47 раз больше подключения на 10 Гбит/с. Локальной настройки против такого не существует. Объёмные атаки должны заканчиваться в сети перед сервером.

Что KernelHost этому противопоставляет

Постоянная защита, которая входит в каждый серверный тариф

Защита от DDoS в KernelHost построена в два уровня и активна постоянно, вам не нужно ничего включать, заказывать или настраивать:

  • Уровень 1: 17 Тбит/с ёмкости митигации в глобальной scrubbing-сети. Объёмные атаки вычищаются близко к источнику, ещё до того как они вообще дойдут до дата-центра.
  • Уровень 2: фильтрация Arbor в реальном времени на 3,2 Тбит/с во Франкфурте-на-Майне. Непосредственно перед сервером распознаются и отбрасываются схемы, характерные для конкретных протоколов, пакет за пакетом.

Решают два свойства. Защита работает постоянно и не должна сначала отреагировать на атаку, то есть нет времени переключения, в которое ваши игроки вылетают. И null-routing не применяется: ваш IP-адрес остаётся в сети, отбрасываются только вредоносные пакеты. Тот, кто убирает IP-адрес из сети, добивается для вас того же результата, что и атакующий. Площадка находится во Франкфурте-на-Майне. Какие игры и протоколы покрыты, перечисляет статья Защита игровых серверов от DDoS в реальном времени.

Advanced DDoS Protection для сообществ под постоянным обстрелом

Некоторые проекты атакуют не время от времени, а прицельно и неделями, с меняющимися схемами и всегда точно в час пик. Для них есть Advanced DDoS Protection от 50,00 € в месяц, по модели PrePaid и без минимального срока. Разница не в большей ёмкости, а в контроле:

  • Выделенный защищённый IP-адрес из франкфуртского ядра сети, на который ваш сервер переводится внутри нашей собственной сети. С вашей стороны ничего перестраивать не нужно.
  • Самостоятельно управляемые правила защиты по портам и протоколам в личном кабинете: вы сами задаёте, что разрешено на 27015/UDP и что на 27015/TCP, и тикет для этого писать не нужно.
  • Изменения вступают в силу в реальном времени, поэтому подстраивать их можно прямо во время идущей атаки, а не ждать следующего технического окна.
  • Профиль защиты под конкретную игру, для Garry's Mod и остальных игр на Source, равно как и свободные TCP- и UDP-профили для модифицированных серверов и собственных приложений.

Здесь тоже действует модель PrePaid: ни минимального срока, ни срока расторжения, ни договора, ни платы за подключение. Когда волна атак пройдёт, вы просто не продлеваете услугу. Тот, кто держит свой Garry's-Mod-сервер пока что в другом месте, получает эту защиту при переезде в KernelHost, ведь фильтрация идёт в нашей собственной сети, а не на чужой инфраструктуре.

Сравнение двух уровней защиты

Характеристика Включённая постоянная защита от DDoS Advanced DDoS Protection
Цена входит в каждый серверный тариф без доплаты от 50,00 € в месяц, PrePaid
Активация работает с момента развёртывания, настраивать нечего заказать, получить защищённый IP-адрес, сервер переводится на него
Ёмкость фильтрации 17 Тбит/с глобального scrubbing плюс фильтрация Arbor в реальном времени на 3,2 Тбит/с во Франкфурте-на-Майне та же двухуровневая фильтрация
IP-адрес IP-адрес вашего сервера дополнительный выделенный защищённый IP-адрес
Набор правил автоматические профили, настраивать ничего не нужно собственные правила по портам и протоколам в личном кабинете
Изменения применяются автоматически вступают в силу в реальном времени, в том числе во время атаки
Игровой профиль оптимизированные профили для распространённых игр, включая Garry's Mod профиль выбирается по портам, в том числе для модифицированных серверов
Null-routing во время атаки нет нет
Срок привязан к серверному тарифу PrePaid, без минимального срока, без срока расторжения, без платы за подключение

Большинству Garry's-Mod-сообществ хватает включённой постоянной защиты вместе с аккуратной настройкой сервера. Advanced DDoS Protection — это ответ на ситуацию, когда кто-то воспринимает происходящее лично.

Частые ошибки и решения

«Сервер работает, но пропал из браузера серверов»: обычно 27015/UDP закрыли целиком или ограничили на нём интенсивность слишком жёстко. Поскольку игровой трафик и запрос делят один порт, грубое правило бьёт по обоим сразу. Работайте вместо этого со сравнением по пакетам без установленного соединения. Если сервер по-прежнему невидим, хотя порт доступен, проверьте sv_setsteamaccount: без действующего Game Server Login Token Garry's-Mod-сервер сильно понижается в списке, и токен нужен свой для каждого сервера.

«Моё правило iptables написано верно и всё равно не работает»: частых причин три. Правило стоит позади цепочек UFW, и дело до него не доходит; оно пропало после последней перезагрузки (тогда помогут apt-get install -y iptables-persistent и netfilter-persistent save или запись в /etc/ufw/before.rules); либо атака объёмная, и правило работает корректно на канале, который уже забит. Проверьте командой iptables -L INPUT -n -v, растут ли счётчики совпадений. Если они остаются на нуле, до правила трафик не доходит.

«Мой DarkRP-сервер тормозит у всех, а канал при этом свободен»: почти всегда это Lua, а не атака на канал. Посмотрите в серверном логе, какое сетевое событие приходит подозрительно часто, и проверьте соответствующий аддон на ограничение по игроку. Если sar -n DEV 1 10 и счётчики отброшенных пакетов ничего необычного не показывают, DDoS-атаки не было.

«RCON внезапно перестал работать»: это не DDoS, а чаще всего своя же блокировка. Админ-панель со старым паролем запускает sv_rcon_minfailures, и sv_rcon_banpenalty блокирует адрес на заданное число минут. Исправьте пароль, снимите блокировку, а затем ограничьте порт своим собственным адресом.

«Я сменил IP-адрес и через два дня снова был офлайн»: это обычное дело. Ваш сервер публикует новый адрес сам, как только снова зарегистрируется на мастер-сервере, а игровой сервер без публичного адреса остаётся без игроков. Смена адреса даёт от нескольких часов до нескольких дней, но решением не является.

«Мой прежний провайдер заблокировал мой IP-адрес»: это и есть null-routing. Так провайдер защищает собственную сеть, а для вас результат ничем не отличается от успешной атаки, обычно ещё на несколько часов после неё. Если сомневаетесь, спросите напрямую: трафик фильтруют или адрес уводят в null-routing. Ответ определяет вашу доступность сильнее, чем любые характеристики железа.

«В tcpdump я не вижу ничего подозрительного»: если трафик отфильтрован ещё в сети перед сервером, то до самого сервера, как и ожидается, ничего не доходит. При работающей фильтрации это нормальная картина. Верно и обратное: при насыщенном канале до вас может не дойти даже та SSH-сессия, из которой вы собирались снимать измерения. Тогда используйте VNC-консоль в личном кабинете.

Коротко о главном

  • Garry's-Mod-серверу нужен ровно один открытый порт: 27015/UDP. Игровой трафик и A2S-запрос идут там вместе, отдельного query-порта не существует.
  • RCON висит на 27015/TCP, передаёт пароль открытым текстом, и открывать его следует исключительно для собственного адреса либо ходить на него через проброс порта по SSH.
  • Ограничивайте не порт, а пакеты без установленного соединения с заголовком 0xffffffff. Сплошная блокировка 27015/UDP выбрасывает ваших же игроков.
  • Самый частый сбой Garry's Mod — это не DDoS-атака, а сетевое событие без ограничения: каждому событию, зарегистрированному через util.AddNetworkString, нужен верхний предел на одного игрока в секунду.
  • При пакетах размером 64 байта канал на 1 Гбит/с несёт около 1,49 миллиона пакетов в секунду. Сверх этого потери возникают на маршрутизаторе перед сервером, и любое локальное правило теряет смысл.
  • В KernelHost двухуровневая постоянная защита входит в каждый серверный тариф без доплаты: 17 Тбит/с ёмкости митигации в глобальной scrubbing-сети и фильтрация Arbor в реальном времени на 3,2 Тбит/с во Франкфурте-на-Майне, без null-routing.
  • Тот, кого обстреливают постоянно и прицельно, добавляет Advanced DDoS Protection от 50,00 € в месяц: выделенный защищённый IP-адрес, самостоятельно управляемые правила по портам и протоколам, действующие в реальном времени.

Если ваш сервер уже работает в KernelHost, фильтрация активна, и делать для этого ничего не нужно. Если вы всё же замечаете странности, откройте тикет в поддержку, чтобы правила фильтрации подстроили под ваш IP-адрес. Укажите сразу четыре вещи: IP-адрес, порт, период в вашем часовом поясе и то, что вы наблюдаете (игроков выбрасывает, сервера нет в браузере, лаги). Во время идущей атаки с нами дополнительно можно связаться через экстренный чат WhatsApp по номеру +43 650 8209883.

Тому, кто помимо Garry's Mod держит и другие игры на Source, общие основы даёт статья Защита CS2- и Source-серверов от DDoS-атак, а как аккуратно поднять всю основу, описано в статье Установка игрового сервера через SteamCMD.

Частые вопросы

Мой Garry's-Mod-сервер сейчас офлайн. Это DDoS-атака?
Смотрите сначала на интенсивность пакетов, а не на загрузку CPU. Команда sar -n DEV 1 10 показывает пакеты и байты в секунду, ip -s link show eth0 счётчики отброшенных пакетов на интерфейсе, nstat -az счётчики ошибок UDP в ядре. Если входящие пакеты уходят далеко за ваше нормальное значение, а подключённых почти нет, это атака. Если сетевые счётчики выглядят спокойно, а тормозит всё равно всё, причина почти всегда в Lua: тогда процессорное время съедает аддон или незащищённое сетевое событие, и никакая фильтрация этого не изменит.
Какие порты действительно нужны Garry's-Mod-серверу?
Ровно один: 27015/UDP, он задаётся параметром запуска -port. Через этот единственный порт вместе идут игровой трафик и A2S-запрос браузера серверов, отдельного query-порта в Garry's Mod нет. RCON висит на 27015/TCP, и открывать его следует исключительно для вашего собственного адреса. 27020/UDP нужен только тогда, когда вы ведёте трансляцию через SourceTV. Клиентский порт 27005/UDP открывается со стороны игрока и правила на сервере не требует. MySQL для DarkRP нужно привязать к 127.0.0.1 и никогда не выпускать в открытую сеть.
Можно ли закрыть query-порт, чтобы поток запросов прекратился?
Нет, потому что отдельного query-порта не существует. Тот, кто закроет 27015/UDP или огульно ограничит на нём интенсивность, тем же движением выбросит собственных игроков и пропадёт из браузера серверов. Правильно ограничивать только пакеты без установленного соединения: все серверные запросы и подключения к серверу в Source-движке начинаются с четырёх байт 0xffffffff, а у трафика уже подключённых игроков такого заголовка нет. Именно на этот признак вешается через nftables или iptables предел по адресу источника, как стартовое значение примерно восемь пакетов в секунду.
Почему RCON в Garry's Mod настолько излюбленная цель атак?
Потому что выигрыш максимальный, а порог входа низкий. RCON висит на том же номере порта, что и игра, только на TCP, и находится без всякого поиска. Протокол Source RCON передаёт пароль открытым текстом, без TLS и без обмена ключами. А тот, кто захватил RCON, меняет карту, банит всех игроков, правит конфигурацию и останавливает сервер, вообще без полосы пропускания. Поэтому задайте длинный случайный пароль, включите sv_rcon_minfailures и sv_rcon_banpenalty и открывайте 27015/TCP только для своего собственного адреса.
Что такое уязвимость A2S-reflection и касается ли она меня до сих пор?
A2S-reflection — это атака, в которой ваш сервер не цель, а инструмент: атакующий опрашивает тысячи игровых серверов с подделанным адресом отправителя, и значительно более объёмные ответы сходятся у настоящей жертвы. Исторически запрос A2S_INFO занимал 25 байт, а US-CERT ведёт протокол Steam с коэффициентом усиления 5,5. Valve закрыла эту брешь начиная с ноября 2020 года: пакеты запросов должны дополняться до 1200 байт, а A2S_PLAYER и A2S_RULES требуют challenge. Держите бинарник сервера в актуальном состоянии, тогда эта защита работает.
Почему моё правило файрвола во время атаки ничего не даёт?
Потому что оно срабатывает лишь тогда, когда пакет уже дошёл. Канал на 1 Гбит/с при пакетах размером 64 байта несёт около 1,49 миллиона пакетов в секунду, канал на 10 Гбит/с около 14,88 миллиона. Если атака больше, потери возникают на маршрутизаторе перед сервером, и ваше правило не будет выполнено никогда. Задолго до того, как канал заполнится, закончится ещё и CPU, ведь каждый пакет стоит одного прохода через сетевой стек, даже если после этого его отбрасывают. С этого места помогает только фильтрация в сети перед сервером.
У моего DarkRP-сервера лаги, а канал при этом свободен. В чём дело?
Тогда это почти всегда Lua, а не атака на канал. Как только аддон регистрирует сетевое событие через util.AddNetworkString и слушает его через net.Receive, любой подключённый клиент может запускать это событие в цикле, и сервер выполняет каждое отдельное сообщение. Хватает одного игрока со скоростью в несколько килобит в секунду. Решение лежит в аддоне, а не в файрволе: верхний предел на одного игрока в секунду, проверка длины сообщения и определение игрока на стороне сервера, а не из содержимого сообщения.
Уйдёт ли мой сервер в KernelHost в офлайн во время атаки?
Нет. Null-routing не применяется. Ваш IP-адрес остаётся в сети, отбрасываются только вредоносные пакеты. Защита построена в два уровня: 17 Тбит/с ёмкости митигации в глобальной scrubbing-сети и фильтрация Arbor в реальном времени на 3,2 Тбит/с во Франкфурте-на-Майне. Она работает постоянно и не должна сначала отреагировать на атаку, то есть нет времени переключения, в которое ваши игроки вылетают. Эта постоянная защита входит в каждый серверный тариф без доплаты и активна с момента развёртывания.
Когда дополнительно нужна Advanced DDoS Protection?
Когда ваше сообщество атакуют не время от времени, а прицельно и неделями, и вы хотите управлять фильтрацией сами. Вы получаете выделенный защищённый IP-адрес и сами задаёте правила защиты по портам и протоколам в личном кабинете, то есть 27015/UDP иначе, чем 27015/TCP. Изменения вступают в силу в реальном времени, поэтому подстраивать их можно прямо во время идущей атаки. Цена начинается от 50,00 € в месяц, по модели PrePaid, без минимального срока, без срока расторжения и без платы за подключение.

Garry's Mod Garrys Mod DDoS-защита DarkRP Source-движок A2S-запрос Защита игровых серверов Порт 27015 Advanced DDoS Protection