Skip to content

v1.9.0

Latest

Choose a tag to compare

@sleep3r sleep3r released this 15 Jun 13:34
568cca3
🇷🇺 Что нового (RU)

Коротко

v1.9.0 добавляет два усиления, отобранных при разборе MTproxy-reanimation (тюнинг-обвязка для Telemt/MTProxyMax). Из пяти её приёмов мы взяли только два — остальные мы уже делаем лучше или они конфликтуют с нашими инвариантами. Апгрейд безопасен: ограничение SYN — опциональное и по умолчанию выключено, а таймаут коннекта к DC — безопасный дефолт, на здоровые соединения не влияет.

Ограничение SYN на уровне ядра (опционально) — mtbuddy setup syn-limit

  • Per-IP ограничение входящих SYN на порту прокси через iptables -m hashlimit. Дропает абьюзные SYN-всплески в ядре, до accept() — там, где наши внутрипроксийные стражи слабее всего (flood guard и per-/24 лимитер работают после accept() и сами по умолчанию выключены, так что каждый абьюзный SYN сейчас всё равно стоит сокета и accept()).
  • Ставится отдельным systemd-oneshot (mtproto-syn-limit.service), поэтому CAP_NET_ADMIN прокси не выдаётся.
  • По умолчанию выключено и с громким предупреждением про carrier-NAT/CGNAT (та же проблема общего egress-IP, из-за которой выключены внутрипроксийные стражи). Пресеты: soft 2/с·burst 5 (дефолт при включении, безопаснее для CGNAT), medium 1/с·3, hard 1/с·1. Предупреждает, если включён accept_proxy_protocol (ядро видит IP балансировщика, а не клиента).
  • Счётчик дропов в mtbuddy status; проверяет, что правило реально применилось (модуль xt_hashlimit на месте), а не молча превратилось в no-op. Идемпотентная установка + полная очистка при uninstall.
  • Взяли iptables (а не nftables), чтобы лечь в существующий стек (TCPMSS, nfqws) — без новой зависимости.
sudo mtbuddy setup syn-limit --preset soft   # soft 2/с·5 | medium 1/с·3 | hard 1/с·1
sudo mtbuddy setup syn-limit --status
sudo mtbuddy setup syn-limit --remove

Per-endpoint таймаут коннекта к DC — dc_connect_timeout_sec (дефолт 10с)

  • Дедлайн на завершение TCP-connect() к каждому эндпоинту Telegram DC. Заблэкхоленный эндпоинт не шлёт RST, и ядро держит SYN_SENT ~2 минуты. handshake_timeout_sec (15с) уже ограничивает весь хендшейк — но глобально, поэтому медленный первый эндпоинт съедает бюджет failover для остальных.
  • Теперь один мёртвый эндпоинт отбрасывается быстро, и failover переходит к следующему в пределах общего потолка handshake_timeout_sec.
  • На здоровые коннекты не влияет (они завершаются за <1с); проверка привязана к фазе .connecting_upstream, поэтому никогда не трогает установленный релей.
  • Сознательно не поднимали handshake_timeout_sec до больших значений — это расширило бы окно для active-probe/slow-loris, против которого заточены DD-логика и flood guard.

Что НЕ взяли (и почему)

  • iOS keepalive sysctl (60/15/3): для нас no-op — на established-сокетах мы уже ставим SO_KEEPALIVE 60/10/3 + TCP_USER_TIMEOUT=30s (жёстче), а host-wide sysctl не достаёт pre-handshake сокеты без SO_KEEPALIVE (их и так жнут idle/handshake-таймауты).
  • iOS MSS=92 + отдельный порт с DNAT: отдельный порт = вторая tg://-ссылка (наши ссылки иммутабельны после раздачи — твёрдое «нет»); MSS-половина конфликтует с нашим TCPMSS=88; и это folk-remedy для iOS-зависания, которое мы уже докопали до клиентского бага MtProtoKit (bad_server_salt) и закрыли client_silence_close_sec (+ апстрим-PR Telegram-iOS#2197).
  • Автодетект деплоя + персист правил в systemd: у нас уже всё это есть для своего стека.

Проверено

zig build test зелёный + кросс-сборки + install-матрица (debian 11/12, ubuntu 20.04/22.04/24.04) + E2E + bench. Изменение в ядре прокси байт-прозрачно и вне happy-path; firewall-фича опциональна и изолирована в своём unit. Документация обновлена во всех README (en/ru/zh/fa/vi) и THREAT_MODEL.


🇬🇧 Release notes (EN)

TL;DR

v1.9.0 adds two hardening features picked from analysing MTproxy-reanimation (a tuning wrapper for Telemt/MTProxyMax). Of its five techniques we kept only two — the rest we already do better or they conflict with our invariants. Upgrading is safe: the SYN limiter is optional and off by default, and the DC connect timeout is a safe default that never affects healthy connections.

Optional kernel SYN rate-limiter — mtbuddy setup syn-limit

  • Per-source-IP inbound SYN rate-limit on the proxy port via iptables -m hashlimit. Drops abusive SYN bursts in the kernel, before accept() — exactly where our in-proxy guards are weakest (the flood guard and per-/24 limiter run after accept() and themselves default off, so every abusive SYN currently still costs a socket + an accept()).
  • Installed as a separate systemd oneshot (mtproto-syn-limit.service), so CAP_NET_ADMIN is never granted to the proxy.
  • Off by default, behind a loud carrier-NAT/CGNAT warning (the same shared-egress-IP problem that keeps the in-proxy guards off). Presets: soft 2/s·burst 5 (default when enabling, CGNAT-safer), medium 1/s·3, hard 1/s·1. Warns when accept_proxy_protocol is set (kernel sees the LB IP, not clients).
  • Drop counter in mtbuddy status; verifies the rule actually landed (xt_hashlimit present) instead of a silent no-op. Idempotent apply + full uninstall cleanup.
  • Uses iptables (not nftables) to match our existing stack (TCPMSS, nfqws) — no new dependency.
sudo mtbuddy setup syn-limit --preset soft   # soft 2/s·5 | medium 1/s·3 | hard 1/s·1
sudo mtbuddy setup syn-limit --status
sudo mtbuddy setup syn-limit --remove

Per-endpoint DC connect timeout — dc_connect_timeout_sec (default 10s)

  • A deadline for completing the TCP connect() to each Telegram DC endpoint. A filtered/black-holed endpoint sends no RST, so the kernel sits in SYN_SENT for ~2 min. handshake_timeout_sec (15s) already caps the whole handshake — but globally, so a slow first endpoint starves the failover budget for the rest.
  • Now one dead endpoint is abandoned fast and failover advances to the next, within the overall handshake_timeout_sec ceiling.
  • Never affects healthy connects (they finish in <1s); the check is gated on the .connecting_upstream phase, so it can never touch an established relay.
  • Deliberately does not raise handshake_timeout_sec — that would widen the active-probe / slow-loris window our DD-decision and flood guards exist to shrink.

Not ported (and why)

  • iOS keepalive sysctl (60/15/3): a no-op for us — relay sockets already set SO_KEEPALIVE 60/10/3 + TCP_USER_TIMEOUT=30s (stricter), and a host-wide sysctl can't touch pre-handshake sockets that lack SO_KEEPALIVE (already reaped by our idle/handshake timeouts).
  • iOS MSS=92 + separate port DNAT: a second port = a second tg:// link (our links are immutable once distributed — hard no); the MSS half conflicts with our TCPMSS=88; and it's a mechanism-free folk remedy for the iOS resume hang we already root-caused to the client MtProtoKit bad_server_salt bug and addressed with client_silence_close_sec (+ upstream PR Telegram-iOS#2197).
  • Deployment autodetection + systemd rule persistence: already implemented for our own stack.

Verified

zig build test green + cross-builds + install matrix (debian 11/12, ubuntu 20.04/22.04/24.04) + E2E + bench. The proxy-core change is byte-transparent and off the happy path; the firewall feature is opt-in and isolated in its own unit. Docs updated across all READMEs (en/ru/zh/fa/vi) and THREAT_MODEL.


Full Changelog: v1.8.1...v1.9.0