Когда нужно защитить передаваемые данные, мы прибегаем к помощи VPN. Однако порой возникает желание скрыть даже сам факт его использования. Так сильно мы заботимся о своей безопасности!?
Поскольку WireGuard сейчас на пике популярности, а он работает на основе протокола UDP, возникла идея замаскировать его трафик под другой популярный протокол на базе UDP — QUIC. QUIC объединяет в себе функции TCP и TLS, поэтому было логично попытаться сделать так, чтобы трафик WireGuard выглядел как трафик QUIC. Для реализации этой идеи потребовалось детально изучить исходный код WireGuard в ядре Linux. Патч для ядра Linux доступен на QUICWireGuard.
Выбор порта
Трафик QUIC использует тот же порт, что и HTTPS — 443. Поэтому WireGuard также будет подниматься на этом порту. Однако, поскольку данное решение предназначено исключительно для работы между двумя устройствами на Linux, мы оставляем возможность подключения других устройств на альтернативных портах. Мимикрия будет активироваться только при использовании порта 443 для WireGuard либо при входящем соединении на этот порт. Во всех остальных случаях WireGuard останется без изменений.
Установка на Arch, Ubuntu, OpenWRT
Для сборки и установки были сделаны два скрипта:
linux_auto_install.sh - подходит для сборки модуля wireguard.ko для данной системы и установки его.
openwrt_auto_install.sh - подходит для сборки модуля wireguard.ko для OpenWRT и установки, как аргумент скрипта надо указать или ssh имя роутера или xxxx@x.x.x.x
Оба скрипта не удаляют из системы предыдущий модуль wireguard.ko. Удаление старого модуля, загрузка обновленного и последующая перезагрузка устройства WireGuard должны выполняться вручную. Чтобы убедиться, что загружена именно новая версия, проверьте вывод команды dmesg | grep -i wireguard
.
[ 8.975692] wireguard: QUICWireGuard 1.0.0 loaded. See https://github.com/karen07/QUICWireGuard for information.
[ 8.975694] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
[ 8.975695] wireguard: Copyright (C) 2024 Karen.
Вы должны увидеть сообщение QUICWireGuard
. Если у вас есть доступ к машине только через WireGuard, будьте особенно внимательны при проверке: всегда существует риск сбоя ядра или неправильной установки. Однако в моей практике таких случаев не возникало.
Для систем, отличных от Arch, Ubuntu и OpenWRT, скрипт также применим, однако вам потребуется добавить в него установку пакетов, необходимых для сборки модуля ядра под ваш конкретный дистрибутив.
Формирование пакета WireGuard
Если открыть код WireGuard в ядре Linux. Там есть файл messages.h, в котором описаны две структуры:
struct message_handshake_initiation {
struct message_header header;
__le32 sender_index;
u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
u8 encrypted_static[noise_encrypted_len(NOISE_PUBLIC_KEY_LEN)];
u8 encrypted_timestamp[noise_encrypted_len(NOISE_TIMESTAMP_LEN)];
struct message_macs macs;
};
struct message_handshake_response {
struct message_header header;
__le32 sender_index;
__le32 receiver_index;
u8 unencrypted_ephemeral[NOISE_PUBLIC_KEY_LEN];
u8 encrypted_nothing[noise_encrypted_len(0)];
struct message_macs macs;
};
Переменных этих структур, отправляются при WireGuard handshake в файле send.c в функциях wg_packet_send_handshake_initiation
и wg_packet_send_handshake_response
. Поэтому если отправлять не только packet
, а еще и QUIC header
, то WireGuard handshake будет похож на QUIC handshake.
struct message_handshake_initiation packet;
wg_socket_send_buffer_to_peer(peer, &packet, sizeof(packet),
HANDSHAKE_DSCP);
struct message_handshake_response packet;
wg_socket_send_buffer_to_peer(peer, &packet,
sizeof(packet),
HANDSHAKE_DSCP);
Описание QUIC header
Если смотреть в WireShark, то QUIC init header
стоит из семи полей.
Поле |
Описание, значение |
Flags |
Битовое поле, заполняю значением |
Version |
Версия, сейчас всегда |
DCID len |
Длина DCID в байтах, для init header значение |
DCID |
Номер получения |
SCID len |
Длина SCID в байтах, для init header значение |
Token len |
Длина SCID в байтах, для init header значение |
Data len |
Состоит из двух частей, первые два бита, первого байта это показатель общей длины Data len, в моем случае 0b01(0x4), а к 0x4 прибавляем длину |
Если смотреть в WireShark, то QUIC response header
стоит из семи полей.
Поле |
Описание, значение |
Flags |
Битовое поле, заполняю значением |
Version |
Версия, сейчас всегда |
DCID len |
Длина DCID в байтах, для response header значение |
SCID len |
Длина SCID в байтах, для response header значение |
SCID |
Номер отправителя |
Token len |
Длина SCID в байтах, для response header значение |
Data len |
Состоит из двух частей, первые два бита, первого байта это показатель общей длины Data len, в моем случае 0b01(0x4), а к 0x4 прибавляем длину |
Соответственно, если спереди к struct message_handshake_initiation packet
добавить QUIC init header
, то начало сессии WireGuard будет похоже на начало сессии QUIC. Тоже самое, если спереди к struct message_handshake_response packet
добавить QUIC response header
, то начало сессии WireGuard будет похоже на начало сессии QUIC.
Прием пакета WireGuard
Открыв код WireGuard в ядре Linux, вы найдете файл receive.c, где обрабатывается прием входящих пакетов. В функции prepare_skb_header
производится удаление заголовка UDP из буфера skb. Нам же понадобится в некоторых случаях удалять также заголовок QUIC. Добавим проверку на номер порта, а также учтем, что все пакеты WireGuard начинаются с числа, не превышающего четыре, тогда как заголовок QUIC начинается с 0xC0
. Таким образом, добавив условие проверки первого байта пакета, мы сможем различать пакеты типа initiation response
и data
.
Результат
Вот пример того, как Wireshark интерпретирует рукопожатие WireGuard. Wireshark определяет соединение как QUIC. Мы достигли желаемого результата.
Комментарии (26)
Semy
23.12.2024 15:59Лучше конечно бы опцией в конфиге.
karen07 Автор
23.12.2024 15:59Конфиг пришлось бы пробросить через весь настроечный пайплайн WireGuard в OpenWRT. Поэтому решение через порт оказалось самым простым для внедрения. Если кто то хочет поменять порт, то этот дефайн легко найти в файле messages.h "#define QUIC_PORT 443"
puchuu
23.12.2024 15:59Для мимикрирования под общение веб сайта и клиента вебсайта нужен сетевой стек браузера либо сам браузер. Не имеет никакого смысла писать обертку вг прямо в квик. Фаерволл легко составит отпечаток поведения этой обертки, дифференцирует этот отпечаток от отпечатка сетевого стека браузера и забанит его. Я почти уверен, что китайский фаерволл уже сделал это, причём сделал сразу как только патч опубликовали.
nidalee
23.12.2024 15:59QUIC в РФ действительно блокируют, просто не очень активно. В зависимости от провайдера, могут либо резать вообще long header, либо фильтровать по SNI из QUIC initial. У некоторых QUIC рубится конкретно в Chrome.
Но суть такова, что QUIC в РФ уже при смерти. Разворачивать на нем что-то нецелесообразно, отключат окончательно в любой момент. Для РКН нет смысла держать его рабочим, он дороже анализируется.
JBFW
23.12.2024 15:59вот лишь бы сломать, лишь бы испортить...
а ведь создавалась эта контора как раз наоборот, типа для борьбы с недобросовестными провайдерами, которые развлекались прозрачными прокси с блокировкой всего что не нравилось (экономия трафика, жалобы обеспокоенных родителей и т.д.)
slinkinone
23.12.2024 15:59QUIC не причем. Дело в TLS ECL расширении. QUIC сам по себе это всего лишь транспорт. Сейчас львиная доля трафика в сети что провайдеров, что мобильных операторов идет с использованием QUIC.
puchuu
23.12.2024 15:59Для мимикрирования под общение веб сайта и клиента вебсайта нужен сетевой стек браузера либо сам браузер. Не имеет никакого смысла писать обертку вг прямо в квик. Фаерволл легко составит отпечаток поведения этой обертки, дифференцирует этот отпечаток от отпечатка сетевого стека браузера и забанит его. Я почти уверен, что китайский фаерволл уже сделал это, причём сделал сразу как только патч опубликовали.
karen07 Автор
23.12.2024 15:59Да, детектировать мимикрию не сложно, но в любом случае сложнее чем чистый WireGuard, который детектируется по двум if.
figachit
23.12.2024 15:59Вы сделали офигенную штуку.
AWG делается для OpenWRT автоматически через Github, может, и вы так же могли бы?
karen07 Автор
23.12.2024 15:59Не совсем понял о чем речь?)
figachit
23.12.2024 15:59Спасибо, что разбанили) уж искал, как с вами связаться
Для AWG есть пайплайны в Github для сбора под любую архитектуру OpenWRT например
karen07 Автор
23.12.2024 15:59посмотрю, но я сделал скрипт, который при наличии линукса без проблем соберет под ваш роутер, просто надо указать его ssh имя)
Kil1J0y
23.12.2024 15:59Я использую haproxy за ним спрятан vless + tls, мне не удалось запустить reality в данной конфигурации, однако, у меня открыты 80 и 443 порт для всего, простой сайт обманка т.к. нужно правдоподобное отрицание висит nextcloud aio на бекенде default, однако магия вся в том что сначала принимаю tcp и если там правила не подошли то идёт на фронтент уже http а там так же sni и маршрутизация пути, wstunnel работает отлично, сейчас в процессе написания скрипта перезапустит сервер wstunnel при падении и так же пишу скрипт клиента для deb12 и openwrt чтоб перезапускал wstunnel, канал на nl 200, загрузил на 140-160 мбит, на уровне с wg где то, но трафик идёт легитимный, в планах также прикрутить stunnel со sni тоже попробовать как socks5, до adguardhome не дошел еще, но прикруьить doh это обязательно, все это тянет на целую статью. С базовыми системами все понятно, с openwrt интереснее, там есть tun2socks, и прикрутить туда маршрутизацию
stanislav37
Вы же в курсе, что в РФ QUIC заблокирован... ?
karen07 Автор
Можете сами проверить, взять свежий curl 8.11.1 с поддержкой HTTP3 и запросить
Semy
Можно запустить в докере:
docker run --rm ymuski/curl-http3 curl --http3-only https://example.org
karen07 Автор
В Arch Linux дефолтный curl уже умеет HTTP3)
onegreyonewhite
Я вот как-то этот момент упустил. А где он заблокирован? У меня сайт на HTTP3 вроде исправно работает.
karen07 Автор
Да, именно протокол никто не блочит)
dartraiden
https://ntc.party/t/ограничение-http3-quic/1823/
Одно время его резали полностью, пока не научились расшифровывать.
slinkinone
Не заблокирован. Я полагаю вы хотели сказать что блокируются потоки, которые используются ECL (Encrypted Client Hello) - расширение для TLS протокола, которое позволяет шифровать запрашиваемый сайт. Так как QUIC использует TLS, то если TLS идущий поверх QUIC использует ECL, то такой поток скорее всего будет заблокирован.