Один из самых частых вопросов, которые нам задают: зачем вообще так усложнять архитектуру, если можно просто поднять сервер и раздавать доступ.Отвечу подробно, и заодно расскажу вещь, о которой мы почему-то редко упоминаем, хотя для этой архитектуры она главная.
Проблема одного сервера
Классический сетап - один или несколько выделенных серверов с постоянными IP-адресами. Он прост в разработке и поддержке, но у него есть фундаментальная слабость: как только адрес попадает в список блокировки, сервис через этот адрес перестаёт работать. Дальше вопрос только в том, насколько быстро адрес найдут.
А найти его не обязательно очень сложно. DPI-оборудование не обязано понимать содержимое каждого пакета - достаточно распознать характерный паттерн трафика, о чём мы говорили в предыдущей статье, а дальше посмотреть, куда этот трафик идёт.
Если адресов мало, их можно обнаруживать и блокировать последовательно.
Просто держать много серверов - тоже не решение само по себе. Это увеличивает эксплуатационную нагрузку, а если значительная часть инфраструктуры принадлежит одному провайдеру или одному ASN, блокировка может затронуть сразу много узлов.
Но есть и более фундаментальная проблема: сколько бы выделенных серверов ни было, это всё равно конечный набор адресов. Если его состав меняется медленно, блокирующей стороне достаточно постепенно поддерживать собственный список в актуальном состоянии.
Сеть - это в первую очередь сами клиенты
И вот здесь находится главное отличие нашей архитектуры, которое в предыдущих рассказах о uTLS, ClientHello и decoy-трафике несколько потерялось.
Устройства пользователей не просто подключаются к сети. Они сами являются её транспортными узлами.
Клиенты образуют mesh и могут ретранслировать пользовательский трафик друг друга - P2P-подобно, как это когда-то делал классический Skype. Поэтому передача данных не сводится к схеме, в которой каждый пользователь обязательно устанавливает соединение с одним из небольшого числа выделенных транспортных серверов.
Это довольно сильно меняет задачу адресной блокировки.
У выделенной серверной инфраструктуры есть более или менее определённый список адресов. У клиентского mesh такого стабильного списка нет. Его состав определяется тем, какие устройства сейчас находятся в сети, и меняется вместе с пользователями.
Конкретный клиентский узел, разумеется, тоже можно обнаружить и сделать недоступным. Mesh не делает IP-адреса невидимыми.
Разница в другом: обнаруженный набор клиентов постоянно устаревает вместе с изменением состава активных участников. Поэтому вместо относительно простой задачи "собрать список серверов и заблокировать его" возникает непрерывная задача обнаружения постоянно меняющегося множества участников.
Это не делает блокировку невозможной. Но заметно меняет её характер.
А что делает опорная сеть
Выделенная инфраструктура у нас всё равно существует. Просто её основная задача другая.
Мы называем её опорной сетью - это она отвечает за доверие и координацию: помогает клиенту узнать, какой конфигурации и каким узлам можно доверять, и обеспечивает выход трафика туда, где это нужно.
Это механизм доверия и координации, а не замена клиентскому mesh.
Здесь полезно разделять две совершенно разные задачи.
Первая - как передать трафик и не сделать несколько серверных IP единственными транспортными точками сети.
Вторая - как клиенту понять, какой конфигурации можно доверять.
Mesh в первую очередь помогает с первой задачей. Опорная сеть решает вторую и обеспечивает вспомогательные функции, включая выход трафика туда, где это необходимо.
А как же DPI
Наличие mesh не отменяет всего того, о чём мы писали раньше.
Если соединения между участниками сети легко классифицируются как трафик, который нужно блокировать, распределённость сама по себе мало поможет. Именно поэтому существуют остальные уровни системы - ротация ClientHello, decoy-трафик и другие меры, усложняющие классификацию соединения.
Это два разных слоя защиты.
Анти-DPI механизмы пытаются сделать отдельное соединение менее удобной целью для классификатора.
Распределённая транспортная архитектура пытается не дать блокировке превратиться в простую задачу ведения небольшого постоянного списка серверных адресов.
Одно другое не заменяет.
Что это стоит
У клиентского mesh есть вполне материальная цена.
Когда устройство передаёт чужой транзитный трафик, оно расходует собственный сетевой трафик и энергию. Особенно заметным это может быть для мобильного устройства, где одновременно ограничены и канал, и батарея.
В комментариях к предыдущей статье уже вспоминали старый Skype именно с этой стороны: участие клиента в P2P-сети было не только преимуществом архитектуры, но и дополнительной нагрузкой на машину пользователя.
Есть и эксплуатационная сложность. Если клиенты становятся частью транспортной инфраструктуры, приходится учитывать нагрузку на отдельное устройство и возможность злоупотребления механизмом ретрансляции. Нельзя исходить из предположения, что каждый клиент располагает ресурсами полноценного сервера.
Точных универсальных цифр здесь нет - расход зависит от того, сколько транзитного трафика проходит через конкретное устройство и в каких условиях оно работает.
Поэтому mesh - не бесплатный способ получить устойчивость. Часть транспортной нагрузки фактически переносится с выделенной инфраструктуры на множество клиентских устройств, а сама система становится заметно сложнее.
Итог
Распределённая архитектура не делает трафик невидимым и не делает сеть неблокируемой.
В нашем случае её главное свойство вообще не связано с количеством разновидностей серверов.
Оно связано с тем, что транспортная сеть состоит в том числе из самих пользователей.
У конечного набора выделенных серверов можно постепенно обнаружить адреса и поддерживать их в блок-листе. У клиентского mesh состав постоянно меняется вместе с составом активных участников сети.
Это не отменяет противостояние с DPI и не решает его раз и навсегда. Но превращает адресную блокировку из задачи поиска относительно стабильного списка серверов в задачу постоянного обнаружения меняющейся сети.
За это приходится платить сложностью, дополнительным транзитным трафиком и ресурсами клиентских устройств. То есть это опять тот же инженерный компромисс: мы усложняем собственную систему, чтобы сделать менее статичной задачу на другой стороне.

