Мониторинг

Обновлено:

Slyber Turn Server включает мощную встроенную систему телеметрии, которая отслеживает активные сессии в реальном времени, ведет 24 часовую почасовую статистику, выявляет атакующие IP адреса и сохраняет данные на диск.

Доступ к служебным эндпоинтам (/metrics, /events, /api/node-stats): Эти маршруты закрыты от посторонних (isInternalOrAuthorized). Доступ к ним разрешен только если:
  1. Передан заголовок X-Turn-Secret (или Authorization: Bearer);
  2. ИЛИ запрос выполнен напрямую с локальной машины (127.0.0.1 / ::1);
  3. ИЛИ IP клиента явно входит в белый список ALLOWED_IPS.

1. Проверка здоровья: GET /healthz

Публичный легковесный эндпоинт для мониторинга сервера:

Bash
curl http://127.0.0.1:8080/healthz
# Ответ (200 OK): {"status":"ok"}

2. Метрики: GET /metrics

Возвращает метрики в стандартном текстовом формате Prometheus (text/plain; version=0.0.4):

  • turn_auth_requests_total{status="success"} (counter) — общее количество уникальных успешных пользовательских подключений к TURN.
  • turn_auth_requests_total{status="failed"} (counter) — общее количество отклоненных попыток авторизации (с учетом 10-секундной дедупликации повторов с одного IP).
  • turn_active_allocations (gauge) — количество активных пользовательских TURN-сессий в данный момент.
  • turn_relayed_bytes_total (counter) — суммарный объем медиа-трафика в байтах, переданный через TURN-релей.
  • turn_ssrf_blocked_total (counter) — количество заблокированных попыток SSRF-атак на приватные и системные адреса.
  • turn_udp_listeners_active (gauge) — количество активных серверных UDP-сокетов (TURN_THREADS).

3. Полная аналитика узла: GET /api/node-stats

Возвращает развернутый JSON слепок состояния сервера для построения дашбордов и панелей управления:

JSON
{
  "status": "online",
  "uptime_sec": 86400,
  "active_sessions": 2,
  "allocated_ports": 3,
  "active_sessions_list": [
    {
      "id": 14,
      "user_id": "user_777",
      "client_ip": "198.51.100.10",
      "relay_port": 49200,
      "transport": "udp (+1 standby)",
      "started_at": "2026-10-27T08:10:00Z",
      "duration_sec": 345,
      "relayed_bytes": 48250112
    }
  ],
  "port_pool_capacity": 16384,
  "port_pool_used_percent": 0.0183,
  "auth_success": 1250,
  "auth_failed": 4,
  "relayed_bytes": 10737418240,
  "ssrf_blocked": 1,
  "lan_skipped": 420,
  "udp_listeners": 8,
  "hourly_24h": [
    {
      "hour_unix": 1761552000,
      "peak_active": 18,
      "connections": 95,
      "relayed_bytes": 524288000,
      "auth_failed": 0,
      "ssrf_blocked": 0
    }
  ],
  "top_offenders": [
    {
      "ip": "203.0.113.199",
      "last_user_id": "attacker",
      "auth_fails": 12,
      "ssrf_blocks": 2,
      "last_seen": "2026-10-27T08:05:12Z"
    }
  ]
}

Особенности подсчета активных сессий и переключения сетей (Wi-Fi ↔ 4G):

  • Таймаут неактивности (maxSessionIdle = 30s): Если по выделенному сокету нет трафика более 30 секунд, он перестает отображаться в списке активных сессий.
  • Умная обработка смены сети (supersededSocketIdle = 5s): Когда пользователь во время звонка выходит из дома и его телефон переключается с Wi-Fi на 4G, создается новая TURN аллокация, а старая замолкает. Сервер видит, что у того же user_id появился свежий активный сокет (с трафиком за последние 3 секунды), и скрывает старый брошенный сокет уже через 5 секунд тишины вместо 30.
  • Группировка сокетов (+N standby): Если клиент открыл несколько параллельных аллокаций (например, для аудио и видео или резервный сокет), они группируются в одну карточку сессии с суммированием трафика и пометкой udp (+1 standby).
  • Рейтинг нарушителей (top_offenders): Сортирует IP адреса по индексу угрозы по формуле: Score = AuthFails + (SSRFBlocks * 5) и возвращает топ-10 самых опасных IP.

4. Журнал событий: GET /events

Сервер ведет в памяти кольцевой буфер последних 2000 событий (SmartEvent). Если одно и то же событие (совпадают тип, user_id, client_ip и target_ip) повторяется в течение 30 секунд, сервер не плодит дубликаты, а увеличивает поле "count" у существующей записи и обновляет ее timestamp.

Параметры фильтрации GET /events:

  • type — фильтр по типу события:
  • ALL (или пусто) — все события.
  • ALERTS — только инциденты безопасности (AUTH_FAIL и SSRF_BLOCK).
  • CREDS_ISSUED — выдача учетных данных через HTTP API.
  • AUTH_OK — успешное установление новой пользовательской TURN-сессии.
  • SESSION_CLOSED — завершение сессии с итоговой сводкой (порт, длительность и объем переданного трафика в B/KB/MB).
  • AUTH_FAIL — ошибка авторизации (неверный формат, истекший TTL, чужой Origin/IP, отсутствие секрета).
  • SSRF_BLOCK — заблокированная попытка SSRF-атаки.
  • user_id — поиск по подстроке user_id (без учета регистра).
  • ip — поиск по подстроке в client_ip или target_ip.
  • limit — максимальное количество возвращаемых записей (от самых свежих к старым).

Пример запроса:

Bash
curl "http://127.0.0.1:8080/events?type=ALERTS&limit=20"

5. Сохранение данных на диск

Чтобы статистика не терялась при перезапуске сервера или обновлении версии, NodeTelemetry каждые 10 секунд (только если были изменения - флаг dirty), а также в момент остановки сервера (SIGTERM/SIGINT) атомарно сохраняет данные в директорию DATA_DIR:

  • stats.json - общие счетчики, 24 часовые корзины hourly и база нарушителей offenders.
  • events.jsonl - журнал событий в формате JSON Lines.

Запись производится сначала во временный файл .tmp с правами 0600, а затем выполняется атомарный os.Rename, что исключает повреждение файлов при внезапном отключении питания.