Protocol
UnixProto
UnixProto — транспорт, на котором работает Unixgram. Он решает одну задачу: доставить сообщение туда и обратно по плохому каналу, не выдавая при этом, что именно передаётся. Ниже — как это устроено.
Путь сообщения
Стек транспорта
Рукопожатие и сессия
Два независимых слоя
Транспорт отвечает за то, как payload нарезан на потоке TCP. Пакет отвечает за то, что внутри одного payload. Слои не знают друг о друге: клиент может выбрать любой транспорт, и формат пакета от этого не изменится.
Пять транспортов
Транспорт выбирается один раз, по первым байтам соединения. Разные варианты дают разный компромисс между накладными расходами и тем, насколько поток похож на случайный шум.
Обфускация
Поток целиком, вместе с тегом транспорта, заворачивается в AES-256-CTR. Это не шифрование — ключ выводится из самого рукопожатия. Задача другая: убрать узнаваемые заголовки, по которым трафик классифицируется как «мессенджер».
Шифрованный канал
Обмен ключами — X25519, затем HKDF-SHA256 даёт 256-битный auth_key. Внутри пакета лежит соль, идентификатор сообщения, метод и параметры. Соль сравнивается за постоянное время, а идентификатор обязан строго возрастать — это защита от повтора. Незашифрованные вызовы сервер отклоняет.
Realtime поверх WebSocket
Второй контур — кадры MessagePack на отдельном порту. Версия протокола согласуется одним числом при рукопожатии и может быть только понижена. Клиент, который просит слишком старую версию, получает терминальный отказ и переходит на резервный канал.
Доставка между репликами
Реестр соединений живёт в процессе, поэтому push, пришедший на одну реплику, сам по себе не увидят клиенты остальных. Каждая отправка публикуется в общий канал Redis, и каждая реплика доставляет своим клиентам сама. Отправитель ждёт свою же копию обратно — иначе локальные клиенты получили бы событие дважды.
Транспорты и их накладные расходы на пакет
| Транспорт | Тег | Кадрирование | Накладные |
|---|---|---|---|
| legacy | — | uint32 BE длина + тело | 4 Б |
| abridged | 0xef | длина/4 одним байтом; 0x7f + 3 Б LE для длинных | 1–4 Б |
| intermediate | 0xeeeeeeee | uint32 LE длина + тело | 4 Б |
| padded intermediate | 0xdddddddd | uint32 LE длина + тело + 0–15 случайных байт | 4–19 Б |
| full | — | длина + seqno + тело + CRC32 | 12 Б |