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

Проблема одного сервера

Классический сетап - один или несколько выделенных серверов с постоянными 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 и не решает его раз и навсегда. Но превращает адресную блокировку из задачи поиска относительно стабильного списка серверов в задачу постоянного обнаружения меняющейся сети.

За это приходится платить сложностью, дополнительным транзитным трафиком и ресурсами клиентских устройств. То есть это опять тот же инженерный компромисс: мы усложняем собственную систему, чтобы сделать менее статичной задачу на другой стороне.