Pull to refresh

Обход блокировок WireGuard в Египте

Reading time5 min
Views50K

В 2021 году VPN протокол WireGuard стал настолько популярен в Египте, что удостоился чести пополнить список заблокированных, несказанно “обрадовав” не только клиентов Cloudflare Warp+, Mullvad Wireguard и других коммерческих VPN-провайдеров, но и некоторых пользователей корпоративных VPN. Предварительные исследования показали, что по всей видимости DPI нацелен на WireGuard Handshake Initiate пакеты, которые имеют фиксированный размер (148 байт) и узнаваемую структуру (первые четыре байта UDP пакета [0x01, 0x00, 0x00, 0x00]).

WireGuard Handshake Initiation
WireGuard Handshake Initiation

Чтобы понять, как DPI может обнаружить и заблокировать WireGuard нужно привнести немного теории. Сам по себе WireGuard протокол предельно простой, трафик упаковывается в совершенно типовой UDP с добавлением небольшого заголовка. Для согласования WireGuard туннеля, как правило, достаточно двух (трех, если считать Keepalive) пакетов:

  • Сторона желающая установить туннель (клиент) отправляет Hadshake Initiation другой стороне (сервер).

  • Если сервер в данный момент готов к подключению, то он отвечает клиенту пакетом Handshake Response.

  • Клиент получает Handshake Response и отвечает Keepalive пакетом, который представляет собой UDP пакет с WireGuard заголовком типа "данные" нулевого размера. В дальнейшем ключи обновляются повторяя описанную процедуру примерно каждые две минуты.

Таким образом, кажется, что для блокировки WireGuard DPI достаточно отслеживать UDP пакеты размером в 148 байт и проверять в них первые четыре байта на соответствие сигнатуре [0x01, 0x00, 0x00, 0x00]. Однако, стоит упомянуть, что корпоративные реализации WireGuard могут использовать зарезервированные три байта (поле Reserved) для собственных нужд (например, в Jamf Private Access они используются как идентификатор сессии). К тому же не исключено, что рано или поздно им найдется применение и в официальном клиенте. Так что для большей точности имеет смысл ограничиться только первым байтом UDP пакета. С другой стороны блокировка всех UDP пакетов размером в 148 байт с первым байтом 0x01 выглядит довольно рискованно. То же самое можно сказать и о Handshake Response пакете, который так же имеет фиксированный размер (92 байта) и схожую сигнатуру с тремя зарезервированными байтами [0x02, 0x00, 0x00, 0x00].

WireGuard Handshake Response
WireGuard Handshake Response

Как же тогда может выглядеть возможный критерий блокировки WireGuard с минимизированной вероятностью ложных срабатываний? По всей видимости DPI стоит пропустить пакет "похожий" на Handshake Initiate, запомнить состояние сессии (IP адреса и порты) и поставить ее на блокировку только после ответного пакета "похожего" на Handshake Response. Нельзя утверждать наверняка, но по косвенным признакам весьма вероятно, что с чем-то подобным мы и имеем дело.

С чего же началась эта история? Скорее всего я не стал бы специально заниматься этой темой, если бы меня неожиданно не заинтересовал пост на форуме, в котором пользователь описывал любопытный метод обхода блокировки WireGuard с помощью другого VPN. Кому интересно, можете почитать нашу переписку, но если в двух словах, то он использовал Windscribe VPN для того, чтобы активировать WireGuard туннель, затем выключал Windscribe VPN и продолжал пользоваться WireGuard (официальный клиент с конфигурацией от Cloudflare Warp+) как ни в чем ни бывало.

В ходе нашего общения постепенно прояснились и прочие подробности, включая государство, которое таким оригинальным способом "подталкивает" население к более глубокому изучению сетевых технологий. Последний раз я был в Египте в 2010 и не могу сказать, что сильно по нему скучаю. Однако в настоящее время это одна из немногих легкодоступных стран, и я в последнее время всерьёз задумывался не слетать ли туда на дайвинг. Надо ли говорить, что невозможность доступа к домашним сетям оказалась бы крайне неприятным сюрпризом.

Далее предстояло решить, что использовать для маскировки Handshake Initiate и Handshake Response вместо Windscribe VPN. Можно конечно построить самописный сервис для инкапсуляции и форвардинга этих пакетов, тем более что нагрузка на него была бы минимальной (два пакета раз в две минуты на туннель). Однако уже довольно давно существует и более подходящий кандидат на эту роль и имя ему SOCKS5. Пятая версия этого популярного протокола поддерживает UDP, что нам собственно от неё и нужно.

Ранее я уже писал о своём пет-проекте VPN клиента на основе Cloudflare реализации протокола WireGuard. В него то я и решил добавить поддержку SOCKS5. В процессе тестирования промежуточных сборок выяснились кое-какие особенности реализации DPI. Например, если первый Handshake Initiate пролетел мимо SOCKS и попал в DPI, то неважно что потом вы отправляете в рамках данной UDP сессии, DPI будет ее настойчиво блокировать. Что любопытно, ничтожная часть пакетов каким-то образом все таки прорывается (возможно их маршрут проходит мимо DPI). Так же похоже, что верно и обратное, если UDP сессия не началась с Handshake Initiate - Handshake Response, то претензий к данной сессии у DPI не будет, даже если эти пакеты покажутся там в дальнейшем. Это могло бы объяснить почему у пользователя WireGuard туннель не ломался через две минуты при следующем Handshake Initiate. Однако это только лишь неподтвержденная гипотеза.

Для поддержки SOCKS5 в Wiresock VPN Client были добавлены следующие дополнительные параметры:

  • Socks5Proxy – указывает адрес и порт сервера SOCKS5, например Socks5Proxy = socks5.sshvpn.me:1080 или Socks5Proxy = 13.134.12.31:1080

  • Socks5ProxyUsername – имя пользователя SOCKS5 (опционально)

  • Socks5ProxyPassword – пароль пользователя SOCKS5 (опционально)

Так же для тестирования нам понадобился SOCKS5 сервер с поддержкой UDP ASSOCIATE. Полагаю большинство читателей вполне способно сконфигурировать такой сервер самостоятельно, поэтому думаю не стоит раздувать размер статьи приводя здесь детальную инструкцию. Остальным же могу порекомендовать памятку, которую я составил для себя по установке Dante от Inferno Nettverk A/S на Ubuntu 20.04 в Oracle Cloud.

Мы протестировали как вариант с применением SOCKS только к Handshake Initiate/Response пакетам, так и полностью ко всем пакетам WireGuard туннеля. Оба варианта прекрасно справились с блокировкой, поэтому остановились на первом, поскольку он более выигрышный с точки зрения производительности и ресурсов. Из неожиданных побочных эффектов, отправка Hanshake Initiate через SOCKS5 прокси "починила" возможность построения вложенного WireGuard туннеля с использованием официального клиента WireGuard for Windows (в качестве внешнего туннеля) и Wiresock VPN Client (в качестве внутреннего), которая "поломалась" где-то между релизами 0.5 и 0.5.3. Официальный клиент внезапно перестал пропускать Handshake Initiate в туннель (возможно это связано с работой по поддержке собственных вложенных туннелей), но после оборачивания в SOCKS он перестал его узнавать и все снова заработало.

Так же хотел отметить, что не представляет большой сложности сделать отдельное Windows приложение для официального клиента, которое будет перехватывать исходящие Handshake Initiate и отправлять их через SOCKS5. Если подобное будет востребовано, то я постараюсь найти время для реализации.

На этом все, надеюсь эта информация будет кому-то полезной!

Tags:
Hubs:
Total votes 17: ↑17 and ↓0+17
Comments38

Articles