Технический разбор для разработчиков

От автора

Я не участвую в разработке Jami и не являюсь профессиональным разработчиком этого проекта. Однако я потратил достаточно времени, изучая архитектуру Jami, тестируя его в российских сетях и разбираясь в документации.

В процессе стало очевидно две вещи:

  • У Jami огромный технический потенциал.

  • В реальных сетевых условиях (особенно в мобильных сетях России) он работает значительно хуже, чем мог бы.

Эта статья — попытка разобрать проблему с инженерной точки зрения и предложить возможные направления развития.

Если вы разработчик, знакомый с C++, сетевыми протоколами, ICE или распределёнными системами — возможно, этот разбор будет вам интересен.


Часть 1. Что такое Jami и почему он интересен

Jami (ранее GNU Ring) — это полностью децентрализованная коммуникационная платформа с открытым исходным кодом, развиваемая компанией Savoir-faire Linux при поддержке сообщества свободного программного обеспечения.

В отличие от большинства популярных мессенджеров, Jami изначально проектировался как peer-to-peer система.

Основные принципы архитектуры:

  • Поиск контактов: использует распределённую хеш-таблицу OpenDHT

  • Соединения между пользователями: устанавливаются напрямую через ICE (Interactive Connectivity Establishment)

  • Регистрация: анонимная — не требуется номер телефона или email.

  • Шифрование: все сообщения и звонки защищены end-to-end encryption, ключи хранятся только на устройствах .

Фактически Jami пытается реализовать модель «пользователь ↔ пользователь» без центральных серверов.

Jami и другие мессенджеры

Мессенджер

Архитектура

📱 Номер телефона

🌐 Серверы

🚫 Блокировки

Telegram

Централизован

Опционально

Telegram

Легко по IP

WhatsApp

Централизован

Обязательно

Meta

Блокируется

Signal

Централизован

Требуется

Собственные

Возможны

Session

Децентрализован

Нет

Lokinet

Сложно

Briar

P2P

Нет

Нет

Почти невозможно

Jami

P2P + DHT

Нет

Bootstrap

Относительно устойчив

При правильной реализации такой подход делает систему очень устойчивой к блокировкам, потому что:

  • нет центрального сервера

  • нет единой точки отказа

  • сеть распределена между пользователями

Однако на практике возникают серьёзные проблемы.

Обзор от Треугольника


Часть 2. Почему Jami работает нестабильно в российских сетях

Я провёл серию тестов в различных сетях (домашний интернет, Wi-Fi, мобильные операторы) и собрал отзывы пользователей. Результаты показали, что основная проблема связана не с самим протоколом, а с особенностями современных сетей.

2.1. CGNAT в мобильных сетях

Большинство мобильных операторов используют Carrier Grade NAT (CGNAT). Это означает:

  • у абонента нет публичного IP-адреса

  • исходящие соединения проходят через общий NAT

  • входящие соединения невозможны

Особенно сложен случай симметричного NAT. В такой ситуации стандартные методы (STUN, UDP hole punching) работают крайне плохо. ICE может пытаться подобрать комбинации кандидатов, но вероятность успешного соединения остаётся низкой.

   Алиса (CGNAT)                      Боб (CGNAT)
   [Устройство] <--- (прямой P2P) ---> [Устройство]
        |                                  |
        |        (не работает)              |
        +----------------------------------+

Один из тестировщиков точно описал ситуацию:

«В мобильных сетях операторы часто используют симметричный NAT (CGNAT). Проброс P2P-соединения через такой NAT — задача нетривиальная. ICE пытается использовать STUN, но часто безуспешно».

2.2. TURN — костыль, который в Р��ссии сломан

Когда прямое соединение установить не удаётся, ICE использует TURN-сервер. TURN (Traversal Using Relays around NAT) работает как ретранслятор:

   Алиса (CGNAT) → TURN-сервер → Боб (CGNAT)

Это решает проблему NAT, но создаёт новые сложности:

  • Весь трафик проходит через сервер → растёт задержка и нагрузка.

  • Публичные TURN-серверы могут быть перегружены или заблокированы.

  • В России встроенные TURN-серверы turn.jami.net недоступны (подтверждено тестами).

  • Поднять свои TURN-серверы на территории РФ бессмысленно из-за DPI и «белых списков» — соединение оборвётся на 16-м килобайте.

  • Jami не поддерживает TURN over DTLS/TLS — TURN-трафик легко детектируется DPI.

В результате TURN остаётся ненадёжным костылём.

2.3. Bootstrap-узлы DHT

Для входа в распределённую сеть клиент должен сначала найти bootstrap-узел. По умолчанию используется bootstrap.jami.net:4222. Если этот узел недоступен или заблокирован, клиенту становится сложнее подключиться к сети.

Проблема решается наличием альтернативных bootstrap-узлов, но в стандартной конфигурации их немного. Сообщество может поднять свои узлы, но они не включены в официальный список .


Часть 3. Каким должен стать Jami, чтобы работать в России

TURN — это архитектурный костыль, от которого необходимо отказаться полностью. Не как опция, а как обязательное требование для работы в современных российских сетях.

Целевая архитектура (без TURN)

Сценарий 1: Прямое соединение через IPv6 / улучшенный ICE

   Алиса (CGNAT, с IPv6)                                       Боб (CGNAT, с IPv6)
   [Устройство] <------------ прямое P2P (IPv6) ------------> [Устройство]
        |                                                           |
        |      (лёгкий сигналинг через DHT)                         |
        +-----------------------------------------------------------+

Что изменилось: Благодаря приоритизации IPv6 и улучшенному ICE клиенты находят друг друга напрямую через глобальные IPv6-адреса. NAT не требуется, TURN не нужен.

Сценарий 2: Ретрансляция через Relay Peer (если прямое соединение невозможно)

   Алиса (CGNAT)                 Relay Peer (Пётр, белый IP)          Боб (CGNAT)
   [Устройство] <------------> [Устройство Петра] <-------------> [Устройство]
        |                      (ретранслирует трафик)                  |
        |                                                              |
        | (обмен ключами и установка канала через DHT)                 |
        +--------------------------------------------------------------+

Что изменилось: Вместо централизованного TURN-сервера используется узел д��угого пользователя (Пётр) с белым IP. Трафик ретранслируется через него, но остаётся зашифрованным end-to-end.

Сценарий 3: Mesh-сеть (множественные пути)

        [DHT-сеть]  (распределённая, для поиска и маршрутизации)
         /       \       \
        /         \       \
   [Алиса]----[Пётр]----[Боб]
       \        /        /
        \  [Мария]      /
         \     |       /
          \----[Иван]--/

Что изменилось: Если нет прямого пути и даже одного ретранслятора недостаточно, сеть строит маршрут через несколько узлов. Протокол динамической маршрутизации выбирает оптимальный путь.


Часть 4. Инженерный план: что необходимо внедрить (для разработчиков)

Я не программист, но я изучил код Jami (доступен на git.jami.net) и документацию. Ниже — конкретные технические задачи, которые нужно решить, чтобы Jami стал по-настоящему неубиваемым.

Уровень 1. Улучшение P2P-соединений

1.1. Приоритизация IPv6 до фанатизма

Где копать: src/ice_transport.cpp, формирование ICE-кандидатов.

Что сделать:

· Принудительно поднять приоритет всех IPv6-кандидатов выше максимального приоритета IPv4.
· В ICE-переговорах форсировать выбор IPv6 даже при чуть худшем RTT.

Почему это необходимо: В российских сотовых сетях IPv6 уже активно раздаётся (МТС, Билайн, Мегафон). Если у обоих абонентов есть глобальные IPv6-адреса — NAT не нужен, P2P работает идеально. Оценка: до 70% мобильных пользователей могут получить прямое соединение.

1.2. Агрессивный UPnP с автоматическим ремаппингом

Где копать: src/upnp/upnp_control.cpp.

Что сделать:

  • Увеличить количество попыток UPnP-маппинга.

  • Реализовать механизм «port prediction» для роутеров, которые последовательно открывают порты.

  • Участить keepalive-пакеты для удержания NAT-маппинга (каждые 15 секунд вместо 60).

Почему это необходимо: Без агрессивного UPnP многие роутеры просто не успевают открыть порт до таймаута ICE.

1.3. Улучшенный ICE для симметричного NAT (CGNAT)

Где копать: патчи к PJSIP в contrib/src/pjproject.

Что сделать:

  • Имплементировать «port inference» — анализ поведения NAT и предсказание следующего порта для конкретного собеседника.

  • Добавить множественные параллельные ICE-переговоры с разными комбинациями кандидатов.

Почему это необходимо: Без этого прямое P2P через CGNAT невозможно в принципе.

Уровень 2. Современные транспортные протоколы

2.1. Переход на QUIC

Статус в Jami: В списке пожеланий есть «Add new transports (e.g. QUIC?)» . Это должно стать приор��тетом.

Где копать: весь стек PJSIP или его замена.

Что сделать: заменить текущую транспортную связку (TCP для signalling, UDP для media) на единый протокол QUIC.

Почему это необходимо:

· QUIC лучше работает через NAT (встроенные keepalive, миграция соединений).
· Мультиплексирование без head-of-line blocking.
· Встроенное шифрование (TLS 1.3) — меньше зависимостей.
· Лучшая адаптация к мобильным сетям (смена Wi-Fi/4G не рвёт соединение).
· QUIC-трафик сложнее детектировать и блокировать DPI.

Уровень 3. P2P-ретрансляция (relay peers)

Если прямое соединение невозможно даже после всех улучшений, нужен механизм, не требующий централизованных серверов.

Идея: Если Алиса и Боб не могут соединиться напрямую, но у них есть общий друг Пётр с белым IP и хорошим каналом, пусть Пётр выступит ретранслятором.

Техническая реализация:

  • Добавить новый тип ICE-кандидата — peer_relay.

  • Узлы с белыми IP могут публиковать в DHT запись: «я готов ретранслировать трафик для до N пользователей».

  • При невозможности P2P клиент ищет в DHT ретрансляторы, доступные обоим абонентам.

  • Трафик идёт по схеме: Алиса → Релей (Пётр) → Боб, с end-to-end шифрованием.

Где копать: потребует изменений в протоколе сигнализации, DHT-схеме и ICE-стеке.

Преимущество: Сеть самоорганизуется. Чем больше пользователей с белыми IP, тем устойчивее становится сеть. Полная независимость от централизованных TURN-серверов.

Уровень 4. Расширенное использование DHT

DHT уже используется для поиска контактов и сигналинга . Теоретически её можно расширить для передачи небольших сообщений (текст, файлы) как в BitTorrent.

Что сделать: исследовать возможность добавления libtorrent (в feature requests Jami уже есть пункт «Add libtorrent support?») .

Почему это необходимо: Это даёт полную децентрализацию для не-медиа трафика.

Уровень 5. Mesh-маршрутизация

В более далёкой перспективе сеть может развиться в оверлейную mesh-архитектуру, где каждый узел знает несколько соседей и строит маршруты динамически (как BATMAN или OLSR).

Преимущество: сеть самоорганизуется и становится устойчивее с каждым новым участником.

Уровень 6. Полное удаление TURN из кодовой базы

Когда P2P, relay peers и mesh-сеть заработают в 99.9% случаев, TURN должен быть полностью вырезан:

  • Удалить relay-кандидатов из ICE (src/ice_transport.cpp).

  • Убрать настройки TURN из GUI.

  • Собрать PJSIP без TURN-поддержки.


Часть 5. Оптимизация: проброс соединения через реле (Hole Punching с координатором)

Внимательный читатель может задать справедливый вопрос: а обязательно ли гнать весь трафик через Петра? Что, если использовать его только как «трамплин» — для первоначального установления связи, а когда канал пробит, убрать его из цепочки и перейти на чистое P2P?

Технически это возможно, и это называется Hole Punching с координатором (Coordinated Hole Punching).

Схема выглядит так:
1. Алиса и Боб находятся за NAT (возможно, симметричным). Прямой Hole Punching не работает или затруднён.
2. Они подключаются к Петру (публичный IP). Пётр видит их внешние адреса: Алиса:PORT_A и Боб:PORT_B.
3. Пётр сообщает Алисе внешний адрес Боба, а Бобу — внешний адрес Алисы.
4. Алиса и Боб одновременно отправляют UDP-пакеты на внешние адреса друг друга.
5. Если NAT «лояльный» (full-cone или address-restricted), он пропустит ответный пакет, и прямое соединение установится. Пётр больше не нужен.

   Алиса (CGNAT)          Пётр (координатор)          Боб (CGNAT)
        |                         |                         |
        |----(1) Привет, я Алиса-->|                         |
        |                         |<---(2) Адрес Боба--------|
        |                         |--------(2) Адрес Алисы-->|
        |                         |                         |
        |----(3) Стучусь к Бобу--------------------------->|
        |<------------------------(3) Стучусь к Алисе-------|
        |                                                   |
        |=========== (4) Прямой P2P-канал пошёл! ===========|
        |                                                   |
        [Пётр больше не участвует]

Почему я не описал это сразу и почему это не отменяет необходимости в ретрансляции?

Потому что это работает не всегда. В современных мобильных сетях доминирует симметричный NAT (тот самый CGNAT). Его поведение убивает эту схему:

  • Когда Алиса стучится к Петру, NAT создаёт правило: «пакеты от Алисы к Петру» с портом PORT_A1.

  • Когда Алиса стучится к Бобу, NAT создаёт новое правило с другим внешним портом PORT_A2.

  • Боб ждёт пакет от Алисы на старый порт (PORT_A1), который он узнал от Петра, но пакет приходит с нового (PORT_A2). Результат — тишина.

Вывод

Использовать реле только для установки соединения — хорошая оптимизация, которую стоит добавить в арсенал ICE. Для 10–20% пользователей с менее строгими NAT она может сработать и снизить нагрузку на ретрансляторы.

Но для оставшихся 80% (симметричный NAT/CGNAT) без постоянной ретрансляции (Алиса → Пётр → Боб) не обойтись. Поэтому стратегия должна быть гибридной:

1. Пытаемся пробить дыру через реле (как описано выше).
2. Если не получилось — включаем полноценную ретрансляцию через того же Петра.


Часть 6. Что может сделать сообщество прямо сейчас

Даже без изменений в основном коде можно предпринять несколько шагов:

  1. Запуск дополнительных bootstrap-узлов в России. Это улучшит доступ к сети.

  2. Тестирование в различных типах NAT. Особенно полезны тесты в мобильных сетях (CGNAT).

  3. Обсуждение новых транспортов (QUIC, relay peers) на форуме Jami (https://forum.jami.net/c/dev).

  4. Создание форка Jami с российскими настройками (российские bootstrap-узлы, приоритет IPv6) и распространение через RuStore.

  5. Эксперименты с peer relay — прототипирование на базе существующего кода.


Заключение

Jami — это не просто мессенджер. Это единственная по-настоящему децентрализованная платформа, которая при правильной реализации может стать абсолютно неуязвимой для блокировок. Никаких серверов, никаких единых точек отказа, никакой зависимости от «доброй воли» провайдеров или регуляторов.

Но сегодня, в российских реалиях 2026 года, Jami не работает. И причина не в злом умысле разработчиков, а в том, что архитектура 10-летней давности не учитывает современных реалий: CGNAT в каждой мобильной сети, тотальный DPI и «белые списки», которые делают TURN-серверы бесполезными.

Что мы теряем прямо сейчас?

Мы теряем возможность иметь инструмент, который:

  • Не требует номера телефона

  • Не хранит метаданные

  • Не зависит от серверов

  • Не может быть заблокирован

Jami мог бы стать этим инструментом. Но пока он остаётся сырой идеей, разбивающейся о суровую реальность сотовых сетей.

Что нужно сделать, чтобы это изменить?

Я не программист. Я не могу написать код. Но я могу чётко сказать, какой код нужно написать:

Что изменить

Где копать

Зачем

IPv6 priority

ice_transport.cpp

70% мобильных пользователей получат прямое P2P

QUIC вместо TCP/UDP

Весь стек PJSIP

Современный транспорт, который не режется DPI

Relay peers

ICE + DHT

Ретрансляция через других пользователей вместо TURN

DHT как транспорт

OpenDHT + libtorrent

Полная децентрализация для текст�� и файлов

Mesh-сеть

Оверлейная маршрутизация

Самоорганизующаяся сеть без единых точек отказа

Кто нужен, чтобы это сделать?

  • C++ разработчики — для изменений в ICE-стеке и транспортном уровне

  • Специалисты по сетям — для работы с QUIC, NAT traversal, DPI

  • Эксперты по DHT — для расширения OpenDHT и интеграции libtorrent

  • Тестировщики — с разными типами NAT (особенно CGNAT)

  • Документаторы — чтобы объяснить изменения сообществу

Что можно сделать прямо сейчас, даже не меняя код?

  1. Поднять российские bootstrap-узлы OpenDHT — это может любой, у кого есть VPS в РФ. Инструкция есть в статье.

  2. Начать обсуждение на форуме Jamihttps://forum.jami.net/c/dev. Создать тему с ссылкой на эту статью.

  3. Сделать форк с российскими настройками — российские bootstrap-узлы, приоритет IPv6, отключение TURN. Выложить в RuStore.

  4. Прототипировать relay peers — взять код и попробовать добавить новый тип ICE-кандидата.

Почему это важно именно сейчас?

Потому что завтра может быть поздно. «Белые списки» уже работают. DPI становится умнее. TURN-серверы отмирают один за другим. Если мы не сделаем Jami по-настоящему P2P сейчас, через год он станет просто ещё одной заблокированной игрушкой.

Jami может стать тем, чем Telegram обещал быть, но не стал — действительно свободным, децентрализованным и неубиваемым мессенджером.

Но для этого нужны не просто обсуждения. Нужен код. Нужны люди, которые готовы взять и сделать.

Кто со мной?

Если вы разработчик — пишите в комментарии, в личку, на форум Jami. Если вы не разработчик, но хотите помочь — распространяйте статью, ищите тех, кто может, тестируйте форки.

Давайте сделаем так, чтобы в России был по-настоящему свободный и работающий P2P-мессенджер. Технически это реально. Осталось только взять и сделать.


P.S. Если у вас есть идеи, как улучшить предложенный план, или вы уже начали что-то делать — делитесь. Нам нужна любая помощь. Этот проект слишком важен, чтобы оставлять его на волю случая.