Skip to content

diagnose: датчик CONN_LIMIT считает loopback, вайтлист и исходящие — постоянная ложная тревога #31

Closed

Description

@jestivald

Симптом

На боевой ноде na-diagnose выдаёт предупреждение о приближении к per-IP лимиту коннектов, которого в реальности нет:

▲ макс. конн. с одного IP = 6790 при CONN_LIMIT=8192 (≥80%) — за CGNAT возможны дропы, подними CONN_LIMIT

Разбор источников на той же ноде:

Пир Коннектов Что это
127.0.0.1 7007 keepalive nginx ↔ xray внутри бокса (каждая пара считается дважды — оба конца в выводе ss)
выход-нода флота 882 исходящие соединения плеча
РФ-вход флота 644 входящие, но адрес в whitelist_v4

То есть предупреждение целиком собрано из трафика, к которому правило ct count неприменимо.

Причина

scripts/diagnose.sh:507-515:

CLIM=$(nft list chain inet na_filter input | grep -oE 'ct count over [0-9]+' | head -1 | grep -oE '[0-9]+')
MAXIP=$(ss -tnH state established | awk '{print $NF}' | sed -E 's/:[0-9]+$//; ...' | sort | uniq -c | sort -rn | head -1 | awk '{print $1+0}')

ss -tnH state established отдаёт все established-сокеты — входящие и исходящие, по всем портам, включая loopback; $NF — адрес пира. Датчик сравнивает это число с CONN_LIMIT.

А само правило (scripts/protect.sh:538-543) заметно уже:

tcp dport ${p} ct state new meter cc4_${p} { ip saddr ct count over ${CONN_LIMIT} } drop

— только ct state new, только на портах из TCP_PORTS, только по ip saddr. И стоит оно в цепочке после двух безусловных accept (живой ruleset, na_filter input):

iif "lo" accept                      # ← loopback не доходит до лимита
ct state established,related accept
ct state invalid drop
ip saddr @whitelist_v4 accept        # ← вайтлист не доходит до лимита
...

Итог: числитель и знаменатель меряют разные вещи. Loopback и вайтлист физически не могут упереться в ct count, исходящие соединения — тем более.

Почему это стоит чинить

Ложная тревога подталкивает ровно к вредному действию — поднять CONN_LIMIT, то есть ослабить защиту от exhaustion, ради проблемы, которой нет. На нодах с внутренним nginx-фолбэком (selfsteal, xHTTP-плечи) loopback-пар всегда тысячи, так что предупреждение там будет гореть постоянно, обесценивая секцию.

Предложение

Считать метрику по тому же срезу, что и правило:

  1. Исключить 127.0.0.0/8 и ::1.
  2. Исключить членов whitelist_v4 / whitelist_v6 (они уже читаются рядом, в проверке дрейфа — scripts/diagnose.sh:495-506).
  3. Считать только входящие на порты из TCP_PORTS — например ss -tnH state established '( sport = :443 or sport = :8445 )' по факту tcp_ports= из protect.installed, группируя по адресу пира.

Как вариант — брать число прямо из conntrack по тем же критериям (conntrack -L -p tcp --dport <p> --state ESTABLISHED), но фильтрация вывода ss дешевле и не тянет зависимость.

Окружение

node-accelerator 4.0.0 (по исходникам v4.0.1 код не менялся), Debian 12/13, XanMod 6.18.47, FW_MODE=strict, CONN_LIMIT=8192, нода с selfsteal-nginx + xHTTP-плечом.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions