惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
D
Docker
D
DataBreaches.Net
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
L
LINUX DO - 热门话题
T
The Blog of Author Tim Ferriss
雷峰网
雷峰网
Project Zero
Project Zero
T
Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
宝玉的分享
宝玉的分享
Stack Overflow Blog
Stack Overflow Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Securelist
Cisco Talos Blog
Cisco Talos Blog
Google DeepMind News
Google DeepMind News
Scott Helme
Scott Helme
The Cloudflare Blog
Know Your Adversary
Know Your Adversary
T
Tor Project blog
博客园_首页
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
Security Latest
Security Latest
Cyberwarzone
Cyberwarzone
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
H
Help Net Security
Simon Willison's Weblog
Simon Willison's Weblog
阮一峰的网络日志
阮一峰的网络日志
C
Cyber Attacks, Cyber Crime and Cyber Security
P
Proofpoint News Feed
AWS News Blog
AWS News Blog
The GitHub Blog
The GitHub Blog
P
Proofpoint News Feed
T
Troy Hunt's Blog
量子位
G
GRAHAM CLULEY
O
OpenAI News
Engineering at Meta
Engineering at Meta
博客园 - Franky
SecWiki News
SecWiki News
F
Fortinet All Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Когда Reality не хватает: добавляем Hysteria2 + Salamander в iOS-мессенджер, и как всегда грабли по дороге (ч.2)
Iaroslav Tager · 2026-05-27 · via Все публикации подряд на Хабре

Средний

9 мин

9.8K

Эту статью я готовил с прошлой недели, и пока готовил, ТСПУ выкатил новые правила фильтрации, целящиеся именно в Reality-handshake, о котором тут речь. То есть статья стала актуальнее, чем когда я её начинал.

В прошлой статье я рассказывал, как мы встроили VLESS + Reality прямо в наше iOS-приложение через sing-box, чтобы обход блокировок был не задачей пользователя, а деталью реализации. Если коротко: TLS-рукопожатие проксируется на посторонний крупный сайт, активный пробинг упирается в этот сайт, IP относимся как к расходнику, конфиг доставляется отдельно от сборки. Подход работает, и для подавляющего большинства соединений из России работает прямо сейчас.

Кроме одного класса сетей, в которых не работал.

Внутри этого класса оказались, в том числе, корпоративные подсети, гостевой Wi-Fi в некоторых аэропортах и часть регионального покрытия одного из операторов. Картина в логах одна и та же. Туннель поднимается, TCP-соединение на relay открывается, TLS-рукопожатие начинается, и через секунду sing-box на сервере пишет в журнал: REALITY: processed invalid connection. Сразу обрыв, нет ретраев которые что-то меняют.

Эта статья про то, что мы увидели в этих сетях, почему Reality в одиночку их не пробивает, и что мы поставили рядом, чтобы пробивал. Если читали предыдущую часть, продолжайте отсюда. Если не читали, важен один тезис: туннель у нас живёт внутри приложения, через sing-box, скомпилированный в нативный фреймворк, без системного VPN.

Что такое «белый список» в DPI

Привычная модель цензуры это чёрный список: оператор знает плохие хосты, режет их, остальное идёт. Обычные методы обхода (Reality, прокси с маскировкой) хорошо работают против чёрного списка, потому что выглядят как «остальное».

Белый список это инверсия. Оператор разрешает трафик к небольшому набору заранее одобренных доменов и IP, а всё, что не подходит под этот список, обрубается с разной степенью аккуратности. На уровне SNI это тривиально: ClientHello открытый, в нём видно куда вы идёте, и если этого домена нет в разрешённом наборе, соединение режется. На уровне IP то же самое: пакеты на адреса вне разрешённого подмножества просто не доходят. Это та же DPI-инфраструктура, что обычно, только настроенная по противоположному принципу.

Тут возникает интересный вопрос. Если белый список идёт по SNI, то Reality, который во время TLS-рукопожатия проксирует трафик на постороний крупный сайт (например, microsoft.com), формально должен пройти: цензор видит в SNI разрешённый домен. Но не проходит. И вот тут начинается интересное.

Что именно ловит белый список DPI

Reality прячет содержимое прокси-туннеля внутри валидного TLS-рукопожатия к разрешённому домену. ClientHello идёт настоящий, отпечатки TLS совпадают с настоящим Chrome (через uTLS), сертификат и цепочка валидные. Пассивный наблюдатель и активный пробер не отличат это от обычного браузера, ходящего на microsoft.com.

Но «не отличит» это про обычный DPI, который смотрит набор сигнатур и принимает решение «разрешать или нет». Белый список DPI ведёт себя иначе. Он не пытается опознать плохой трафик, он пытается убедиться в хорошем. И это другой алгоритм.

Тут оговорюсь сразу: я не ковырял исходники конкретного DPI-вендора, и формулировка ниже это моя реконструкция по поведению, а не подтверждённая истина. Параллельно я задавал вопросы знакомым из тель-авивского инженерного слоя (на стороне коммерческих DPI-вендоров там исторически плотно), и формулировка, которую от них слышал чаще всего, звучит примерно как «современные продукты не опознают плохое по одной сигнатуре, они собирают уверенность что трафик хороший из нескольких признаков сразу». Это согласуется с тем, что мы наблюдали, но это всё равно эвристический вывод снаружи.

Дальше я просто перечислю, что в этой картине, по моим наблюдениям, влияет. Если ваше «обращение к microsoft.com» отличается от настоящего по любому набору микро-параметров, эвристика поднимает руку. И таких параметров много: порядок TLS-расширений в ClientHello, паттерн GREASE-значений, тайминги ответов после рукопожатия, размеры записей. uTLS аккуратно копирует ClientHello Chrome версии N, но реальный Chrome ещё и ходит по сети как Chrome: подключение из обычного браузера тянет за собой TCP fast open, HTTP/2 PING-фреймы в характерные моменты, OCSP-staple проверки, ALPN-переговоры, и десятки других мелочей.

Reality всё это не воспроизводит. Reality безупречно вышел из TLS-рукопожатия и переключился на туннель, и дальше через канал идёт ваш прокси-трафик. С точки зрения DPI это TLS на microsoft.com, в котором сразу после рукопожатия начинается странный поток данных, не похожий на HTTPS. Для классического чёрного списка это пройдёт, потому что сигнатуры «странности» в нём не прописаны явно. Для белого списка, где эвристика по умолчанию говорит «не разрешать, если не убедился», этого хватает чтобы зарезать.

Мы попробовали несколько настроек: разные SNI для маскировки, разные uTLS-отпечатки (chrome 120, chrome 131, firefox), разное поведение xtls-rprx-vision. Картина не менялась. Это не вопрос подобрать правильный отпечаток, это вопрос самой парадигмы.

Значит, в этих сетях нужен другой подход.

Почему UDP, и почему именно Hysteria2

В TCP-мире DPI на белый список это решённая задача с понятным ответом: смотрим на TLS, сравниваем со списком, режем неподходящее. В UDP-мире у DPI задача сложнее, потому что UDP сам по себе разный. QUIC к youtube.com и QUIC к Cloudflare и игровой трафик и видеозвонки и просто чей-то самописный протокол выглядят достаточно по-разному, чтобы единая эвристика «это разрешённый UDP» работала плохо. И слишком агрессивно резать UDP опасно для самой сети: половина мобильного трафика сейчас идёт по QUIC, ломать QUIC к крупным сайтам это себе же в ногу.

Поэтому UDP-транспорты в практическом обходе блокировок ведут себя лучше. Но просто QUIC «как есть» это тоже не решение: QUIC-handshake тоже маркируется, и DPI, который натренирован на конкретных публичных версиях QUIC (Chrome, Cloudflare, Google QUIC v1), может опознать и его.

Hysteria2 это собственный протокол поверх QUIC, ориентированный именно на обход блокировок. И главное, что нас интересовало, это его obfs-плагин по имени Salamander. Salamander накладывает на каждый UDP-пакет внешний XOR-слой с ключом, который выводится из пароля. То есть DPI, который попытается посмотреть в первый пакет hy2 и опознать QUIC-handshake по байтам, видит просто бессмысленный поток. Никаких узнаваемых сигнатур внутри пакета не выживает.

Стороны (клиент и сервер) знают пароль, выводят из него ключ, и пишут/читают одинаково. Снаружи не видно ничего полезного.

Этого вполне достаточно для того DPI, что нам нужно было обойти. Подчеркну «вполне достаточно для того» сознательно: я не знаю, как этот же подход поведёт себя на других реализациях DPI, и предположение «UDP+obfs всегда лучше» в общем виде наверняка неверно. Конкретно в наших сценариях оно сработало.

Как это устроено

Архитектура простая. Тот же relay-сервер, на котором уже жил VLESS + Reality на TCP/443, теперь дополнительно слушает hy2 на UDP/443. Один порт, разные транспорты, никакого конфликта (TCP и UDP это разные стеки в ядре).

Серверный конфиг sing-box, ядро:

{ "inbounds": [{ "type": "hysteria2", "listen": "::", "listen_port": 443, "users": [{ "password": "..." }], "obfs": { "type": "salamander", "password": "..." }, "tls": { "enabled": true, "server_name": "www.apple.com", "certificate_path": "/etc/sing-box/hy2_cert.pem", "key_path": "/etc/sing-box/hy2_key.pem" } }] }

Два пароля, не один. Первый это аутентификация пользователя на hy2. Второй это пароль для Salamander, отдельный, потому что obfs работает на слое до того, как мы вообще разбираем hy2-пакет. Если obfs-пароль не совпал, сервер вообще не поймёт что к нему пришло.

Сертификат self-signed, на тот же CN, что и SNI разрешённого домена (мы используем тот же домен, что и в Reality, по соображениям связности логов и по тому, что cert CN внутри TLS виден только клиенту, для DPI он внутри obfs-слоя и не имеет значения). Клиент ходит с insecure: true, потому что аутентификация выносится на пароли, не на PKI.

Клиентский outbound (тот же sing-box, тот же фреймворк, что и в первой статье):

{ "outbounds": [{ "type": "hysteria2", "server": "RELAY_ADDR", "server_port": 443, "password": "...", "obfs": { "type": "salamander", "password": "..." }, "tls": { "enabled": true, "server_name": "www.apple.com", "insecure": true } }] }

Один нюанс по сборке gomobile. Если вы собирали sing-box для прошлой статьи, у вас уже есть тег with_utls. Под hy2 + obfs понадобится дополнительно with_quic, иначе нужные модули просто не попадут во фреймворк. На размер бинарника это влияет ощутимо (десятки мегабайт), но это плата за UDP-транспорт, ничего не поделать.

Как клиент выбирает между Reality и hy2

В sing-box есть outbound типа urltest, который параллельно поднимает несколько подоблочных outbound и выбирает самый быстрый по результатам HTTP-проб. Мы сложили в urltest оба варианта, Reality и hy2, для каждого relay. На сетях, где Reality проходит, побеждает он (на TCP мы получаем чуть меньшую латентность). На сетях с белым списком Reality проба тихо не проходит, hy2 проходит, urltest это видит и переключает основной поток на hy2.

Пользователь ничего не настраивает. Приложение в первый раз делает прямое подключение, если не получается, поднимает sing-box, sing-box внутри себя выбирает рабочий транспорт.

Грабли по дороге

С самим протоколом и с конфигами всё было аккуратно, документация sing-box достаточная. Грабли вылезли в инфраструктуре.

Облачные файрволы на UDP. На этой грабле я честно потерял часть вечера, и пишу про неё подробно, потому что это та категория ошибок, в которой ты долго винишь свой конфиг. На двух хостингах из четырёх iptables на самой машине настроили правильно (UDP/443 ACCEPT), сертификаты разложили, sing-box стартанул и слушает, всё хорошо. Снаружи трафика на машину не приходит вообще. Сидишь с tcpdump на хосте, видишь ноль пакетов, и думаешь «что я сломал в iptables», хотя в iptables всё в порядке. Это не баг конфига, это облачный firewall на уровне провайдера, который по умолчанию открывает только привычные порты, а UDP/443 закрыт. У одного из них, к слову, у API-роли инстанса не оказалось права открывать порты программно, пришлось руками заходить в UI. У второго подобная история была с named security group. Это пятиминутная задача, когда вы знаете, что её надо сделать, и часовое расследование, когда не знаете.

Урок: после того, как вы подняли listener на новом порту, обязательно проверяйте c посторонней машины, что пакеты доходят. Никогда не верить «iptables говорит open», верить tcpdump на машине, в котором вы видите входящие пакеты. И если tcpdump молчит, искать причину не в правилах самой машины, а слоем выше.

Один общий SNI для пары транспортов на одном relay. Внутри Reality TLS-рукопожатие настоящее, проксируется на microsoft.com (например), и cert CN должен соответствовать. Внутри hy2 TLS зашифрован obfs-слоем и снаружи не виден, но cert CN тоже microsoft.com, чтобы внутренние логи и панель администрирования не выглядели разнокалиберно. Это не функциональная необходимость, это операционная гигиена, чтобы через полгода смотреть в логи и не теряться.

Self-signed cert и insecure: true. Это нормально для hy2 с паролями, но при первом запуске рука сама тянется проверять «а валидный ли cert». Не валидный, и это нормально. Вся аутентификация на паролях. Если вы для какого-то будущего этапа захотите выпустить настоящий cert (через DNS-01 challenge на поддомен relay), это не сделает hy2 лучше с точки зрения обхода, это просто уберёт строку с insecure из конфига клиента.

Hosting diversity сильнее, чем кажется. Reality горит по IP, и hy2 горит по IP примерно так же. Имеет смысл, чтобы пара (Reality, hy2) у вас была на разных провайдерах, в разных регионах. Если cidr одного провайдера попадает под массовый блок, у вас остаются другие. Мы держим набор из нескольких сочетаний (один провайдер, второй провайдер, третий) и в конфиге, который доставляется отдельно от сборки, прописаны они все. Подробнее об этом подходе писал в первой статье.

Честно про границы

Уже писал в первой статье, повторю кратко: туннель меняет то, как соединение выглядит для цензора по дороге, и не меняет того, кто стоит на концах. Содержимое переписки защищается отдельно, на уровне приложения (мы используем libsignal). Hy2 + Salamander это про другой слой: про то, чтобы пакеты вообще доходили до сервера.

Salamander обфускация на пароле, не на полноценной криптографии. Если пароль вытащить (например, из вашей же скомпрометированной сборки), obfs снимается тривиально и DPI снова видит QUIC-handshake внутри. Поэтому пароли мы (как и всё, что должно быстро меняться) храним не в бинарнике, а в подписанном конфиге, который доставляется в рантайме. Сменили relay, сменили пароли, перевыпустили подпись, клиент подтянул.

Ещё одно важное наблюдение, которое мы видим по логам и обратной связи. Даже с hy2 в дополнение к Reality у части пользователей всё равно не поднимается транспорт. Это меньшинство, но устойчивое. По косвенным признакам (геолокация, оператор, время суток когда проблема обостряется) картина довольно последовательная: чем ближе сеть пользователя к зонам с особо чувствительной для государства активностью, тем плотнее настроены белые списки и тем агрессивнее режется всё, что не вписывается. То есть DPI это не однородный слой по стране, это градиент с локальными ужесточениями. Я не могу это доказать строго, у меня нет доступа к настройкам ни одного оператора, но картина совпадает у достаточного числа пользователей, чтобы упоминать это как наблюдение, а не совпадение.

И отдельно: всё это гонка. Сегодня белый список DPI не умеет хорошо резать обфускированный UDP, через год может научиться. Это нормальный процесс, к нему просто надо относиться как к процессу: иметь запас инструментов, мониторить, что отвалилось, и не считать ни один из них «навсегда».

Что забрать

Если вы делаете похожую задачу:

В сетях с белым списком DPI один Reality поверх TCP может не сработать, потому что DPI работает не на «опознать плохое», а на «убедиться в хорошем». Это другая парадигма, и Reality в неё не попадает по построению.

UDP + obfs (в нашем случае Hysteria2 + Salamander) в этих сетях работает лучше, потому что UDP-DPI в принципе слабее, а Salamander дополнительно убирает любые сигнатуры внутри пакета.

Не выбирайте один транспорт, держите оба. Reality экономит ресурс на сетях без белого списка, hy2 пробивает то, что Reality не пробивает. urltest в sing-box решает это автоматически.

Облачные firewall на UDP это отдельная тема и почти всегда отдельная боль. Закладывайте время на «открыть нужный порт в UI провайдера», особенно если у вас несколько разных провайдеров.

И сразу планируйте, что и hy2, и Reality будут гореть по IP. Один из них может прожить дольше, но оба расходники. Конфиг доставляется отдельно от сборки, иначе каждый горящий IP это новый релиз в App Store.


Всё, что описано, живёт в нашем мессенджере RCQ, сейчас он в открытой бете на iOS. Клиент с открытым исходным кодом, можно посмотреть, как именно устроен транспорт и переключение между ним: github.com/rcq-messenger/rcq-ios.

Если занимаетесь похожим и видели у себя поведение белого списка DPI или работали с hy2 в проде, расскажите в комментариях. Особенно интересно про сети, в которых не сработал ни Reality, ни hy2: с такими мы пока не встречались, но это не значит, что их нет.