Технический разбор для разработчиков
От автора
Я не участвую в разработке 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 |
Централизован | Обязательно | 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. Что может сделать сообщество прямо сейчас
Даже без изменений в основном коде можно предпринять несколько шагов:
Запуск дополнительных bootstrap-узлов в России. Это улучшит доступ к сети.
Тестирование в различных типах NAT. Особенно полезны тесты в мобильных сетях (CGNAT).
Обсуждение новых транспортов (QUIC, relay peers) на форуме Jami (https://forum.jami.net/c/dev).
Создание форка Jami с российскими настройками (российские bootstrap-узлы, приоритет IPv6) и распространение через RuStore.
Эксперименты с peer relay — прототипирование на базе существующего кода.
Заключение
Jami — это не просто мессенджер. Это единственная по-настоящему децентрализованная платформа, которая при правильной реализации может стать абсолютно неуязвимой для блокировок. Никаких серверов, никаких единых точек отказа, никакой зависимости от «доброй воли» провайдеров или регуляторов.
Но сегодня, в российских реалиях 2026 года, Jami не работает. И причина не в злом умысле разработчиков, а в том, что архитектура 10-летней давности не учитывает современных реалий: CGNAT в каждой мобильной сети, тотальный DPI и «белые списки», которые делают TURN-серверы бесполезными.
Что мы теряем прямо сейчас?
Мы теряем возможность иметь инструмент, который:
Не требует номера телефона
Не хранит метаданные
Не зависит от серверов
Не может быть заблокирован
Jami мог бы стать этим инструментом. Но пока он остаётся сырой идеей, разбивающейся о суровую реальность сотовых сетей.
Что нужно сделать, чтобы это изменить?
Я не программист. Я не могу написать код. Но я могу чётко сказать, какой код нужно написать:
Что изменить | Где копать | Зачем |
|---|---|---|
IPv6 priority |
| 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)
Документаторы — чтобы объяснить изменения сообществу
Что можно сделать прямо сейчас, даже не меняя код?
Поднять российские bootstrap-узлы OpenDHT — это может любой, у кого есть VPS в РФ. Инструкция есть в статье.
Начать обсуждение на форуме Jami — https://forum.jami.net/c/dev. Создать тему с ссылкой на эту статью.
Сделать форк с российскими настройками — российские bootstrap-узлы, приоритет IPv6, отключение TURN. Выложить в RuStore.
Прототипировать relay peers — взять код и попробовать добавить новый тип ICE-кандидата.
Почему это важно именно сейчас?
Потому что завтра может быть поздно. «Белые списки» уже работают. DPI становится умнее. TURN-серверы отмирают один за другим. Если мы не сделаем Jami по-настоящему P2P сейчас, через год он станет просто ещё одной заблокированной игрушкой.
Jami может стать тем, чем Telegram обещал быть, но не стал — действительно свободным, децентрализованным и неубиваемым мессенджером.
Но для этого нужны не просто обсуждения. Нужен код. Нужны люди, которые готовы взять и сделать.
Кто со мной?
Если вы разработчик — пишите в комментарии, в личку, на форум Jami. Если вы не разработчик, но хотите помочь — распространяйте статью, ищите тех, кто может, тестируйте форки.
Давайте сделаем так, чтобы в России был по-настоящему свободный и работающий P2P-мессенджер. Технически это реально. Осталось только взять и сделать.
P.S. Если у вас есть идеи, как улучшить предложенный план, или вы уже начали что-то делать — делитесь. Нам нужна любая помощь. Этот проект слишком важен, чтобы оставлять его на волю случая.
