В этом посте я кратко поведаю о разных интересных возможностях XRay (клиент и сервер для протоколов VMess, VLESS, Trojan и других, в том числе с XTLS-Reality и XTLS-Vision), о которых, кажется, мало кто знает, но которые могут оказаться очень полезными.
Оглавление:
-
Фрагментирование запросов
-
QUIC-транспорт
-
Мониторинг и автоматический выбор outbound'а
-
Сбор статистики
-
Browser dialer
Fragment
На фоне недавних событий (замедление Youtube Роскомнадзором), многие открыли для себя инструменты типа GoodbyeDPI и подобных. Они работают с использованием различных трюков при передаче данных по протоколу TCP, благодаря которым цензурирующее оборудование (так называемое ТСПУ) при обработке TLS-handshake оказывается сбитым с толку и не понимает, на какой именно сайт вы пытаетесь попасть (потому что не может прочитать параметр "SNI" при установке TLS-соединения), и в итоге блокировка/замедление не срабатывает. XRay тоже умеет подобное, там это называется "Fragment".
Простейший конфиг XRay для этого будет выглядеть примерно так:
локальный прокси с fragment
{
"inbounds": [
{
"listen": "127.0.0.1",
"port": 1080,
"protocol": "socks",
"tag": "socks"
}
],
"outbounds": [
{
"tag": "fragment",
"protocol": "freedom",
"settings": {
"fragment": {
"packets": "tlshello",
"length": "100-200",
"interval": "10-20"
}
},
"streamSettings": {
"sockopt": {
"tcpNoDelay": true
}
}
}
]
}
Запустив XRay с таким конфигом и настроив браузер на использование SOCKS-прокси на локальном (127.0.0.1) порту 1080, XRay будет фрагментировать заголовок ClientHello протокола TLS. Доступные параметры:
"packets"
:может быть "1-3" для фрагментации на уровне TCP (первые 1-3 отправки данных от клиента к серверу) либо "tlshello" для фрагментации TLS handshake;
"length"
: на кусочки какого размера дробить отправляемые данные;
"interval"
: пауза между отправкой фрагментов в миллисекундах;
Конкретные требуемые значения параметров могут отличаться в зависимости от типа (и даже версии софта) используемого оборудования DPI у провайдера, поэтому возможно чтобы получить нужный эффект придется с ними поэкспериментировать.
Fragment можно также комбинировать с использованием прокси-протоколов, например VLESS и других, пример конфига есть на github.
QUIC-транспорт
Еще из того, о чем недавно говорили на фоне замедления Youtube - протокол QUIC. Это разработка Google, которая использует UDP вместо TCP при доступе к веб-серверам, нацеленная на уменьшение времени установки соединения и улучшение скорости доступа за счет более эффективной передачи данных. В случае с замедлением Youtube у некоторых пользователей включение QUIC в браузере помогло решить проблему (а у некоторых наоборот, выключение). Причин тут может быть несколько. Во-первых, есть основание предполагать, что определенное оборудование ТСПУ... не умеет нормально разбирать заголовки QUIC-протокола (и из-за этого одно время Роскомнадзор даже резал такие подключения). Во-вторых, в браузере Chrome разработчики намеренно добавили фрагментацию данных при установке соединения - они таким образом пытались заставить разработчиков веб-серверов полностью следовать стандарту протокола, и эта фрагментации дала очень полезный побочный эффект для обхода цензуры (см. предыдущую часть статьи). В третьих, QUIC очень эффективно работает при потерях пакетов, а оборудование РКН замедляет Youtube именно таким образом.
И XRay умеет использовать QUIC в качестве транспорта для своих протоколов (VLESS, VMess, Trojan и другие). Вы можете спросить, зачем использовать QUIC-транспорт, когда можно использовать VLESS безо всяких транспортов (поверх обычного TLS), отвечу - всегда полезно иметь запасной альтернативный вариант, к тому же QUIC в XRay можно использовать по-разному.
Вариант раз - в чистом виде. С QUIC, к сожалению, не получится сделать что-то типа XTLS-Reality, когда вы прикрываетесь чужим доменом. В теории это возможно, но пока что никто такое не реализовал. Поэтому понадобится свой домен и TLS-сертификат для него (подойдет даже бесплатный домен от dynu.com и сертификат от LetsEncrypt). Конфиг XRay для примера:
VLESS c QUIC-транспортом
{
"inbounds": [
{
"port": 443,
"protocol": "vless",
"tag": "quic",
"settings": {
"clients": [
{
"id": "4c3fe585-bb09-89df-b284-e2dada14150f",
"email": "user1"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "quic",
"quicSettings": {},
"security": "tls",
"tlsSettings": {
"certificates": [
{
"certificateFile": "/etc/letsencrypt/live/yourdomain/fullchain.pem",
"keyFile": "/etc/letsencrypt/live/yourdomain/privkey.pem"
}]
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"quic",
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
Потом в клиенте настраиваете VLESS-подключение с нужным UUID, вводите адрес (домен) вашего сервера, выбираете QUIC в качестве транспорта - и все работает. Такое подключение будет со стороны выглядеть как настоящий QUIC на 443 UDP порту, но, к сожалению, настроить fallback (чтобы при заходе на UDP/443 открывался фейковый веб-сайт) в XRay возможности нет.
Второй вариант - использовать обфусцированный QUIC. Домен и сертификат для этого уже не нужны (их все равно никто не увидит). Со стороны передача данных будет выглядить как "нечто непонятное по UDP", примерно как в случае с AmneziaWG.
VLESS + обфусцированный QUIC (что-то непонятное по UDP)
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"port": 8443,
"protocol": "vless",
"tag": "quic",
"settings": {
"clients": [
{
"id": "4c3fe585-bb09-89df-b284-e2dada14150f",
"email": "user1"
}
],
"decryption": "none"
},
"streamSettings": {
"network": "quic",
"quicSettings": {
"security": "aes-128-gcm",
"key": "hellohabr"
}
},
"sniffing": {
"enabled": true,
"destOverride": [
"quic",
"http",
"tls"
]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
В данном случае используется шифр aes-128-gcm
(другой возможный вариант - chacha20-poly1305
) с ключом"hellohabr". Клиенты настраиваются аналогично предыдущему случаю, только надо отключить TLS, а вместо этого выбрать шифр и ключ.
И еще один вариант, близкий ко второму - замаскировать QUIC под DTLS (WebRTC, звонки в месседжерах), SRTP (FaceTime) или uTP (BitTorrent). Для этого нужно добавить параметр header:
...
"streamSettings": {
"network": "quic",
"quicSettings": {
"security": "aes-128-gcm",
"key": "hellohabr",
"header": {
"type": "dtls"
}
}
...
"type" может быть "srtp", "utp", "dtls", "wechat-video" и "wireguard". Не забудьте на клиенте выбрать то же самое.
Помните, я в своей статье "Надежный обход блокировок в 2024: протоколы, клиенты и настройка сервера от простого к сложному" (заблокирована на территории РФ, но доступна через иностранные VPN/прокси) советовал mKCP как запасной вариант, работающий по UDP? К сожалению, начиная с какой-то из версий Xray оно сломано и тупит при определенных сценариях - жрет память, жрет процессор и тормозит, вплоть до полной невозможности работы. Транспорт QUIC в XRay работает гораздо стабильнее, и обладает всеми теми же возможностями обфускации.
Недостатка два. Первый, как я уже сказал, когда вы маскируетесь под "чистый" QUIC, нельзя добавить маскировочный сайт. Второй - вся эта красота работает только с клиентами на базе XRay-core, а те что на базе Sing-box в пролете (точнее, sing-box не поддерживает обфусцированный QUIC, чистый в теории должен работать, но не заработал).
Если вам нужен прокси поверх QUIC с маскировкой под сайт или под "непонытно что" и работающий с Sing-box, используйте Hysteria2.
Selectors и observatory - мониторинг и автоматический выбор outbound'а
Некоторые используют XRay для построения цепочек прокси. Например, вы находясь в России подключаетесь сначала к прокси-серверу находящемуся в России, а уже с него куда-нибудь за бугор. XRay позволяет контролировать доступность вышестоящих прокси-серверов (если у вас их несколько) и балансировать запросы между ними. Фичи называются selectors и observatory. Документация здесь.
Расскажу про конфиг вкратце. На верхнем уровне вашего конфига добавляете объект "observatory":
"observatory": {
"subjectSelector": [ "outbound1", "outbound2" ],
"probeURL": "http://www.gstatic.com/generate_204",
"probeInterval": "300s",
"enableConcurrency": true
},
В списке "subjectSelector" перечисляете имена outbound'ов которые надо проверять, в "probeURL" задаете адрес для теста, в "probeInterval" периодичность.
А потом в объекте "routing" описываете объект "balancers", например так:
"routing": {
"domainStrategy": "IPIfNonMatch",
"balancers": [
{
"tag": "mybalancer",
"selector": [ "outbound1", "outbound2" ],
"strategy": {
"type": "leastPing"
},
"fallbackTag": "outbound3"
},
В "selector" перечисляете outbound'ы, через которые можно подключаться "наружу", в fallbackTag можно указать outbound который XRay попытается использовать если все перечисленные выше окажутся недоступные (и он же будет использоваться сразу после старта пока еще не прошли проверки). И дальше вы можете использовать ваш "mybalancer" как обычный outbound - например указать его явно в правилах роутинга.
Сбор статистики
Можно получать в виде JSON статистику - кто из пользователей сколько скачал, по каким inbound'ам/outbound'ам, а если используете observables из предыдущего раздела - смотреть их доступность и время пинга. Удобно для интеграции в системы мониторинга типа Munin, Zabbix или Prometheus. Документация здесь: Метрики | Project X (xtls.github.io)
Browser dialer
Помните про TLS-fingerprint, он же отпечаток? У каждого браузера и каждой TLS-библиотеки он уникальный. В некоторых странах цензоры уже используют его для выявления подключений от прокси-клиентов, потому что у стандартной TLS-библиотеки языка Go он совсем не похож на отпечатки популярных браузеров. XRay может использовать uTLS - специально модифицированную библиотеку, которая умеет "прикидываться" браузерами, например, firefox и chrome, копируя их fingerprint'ы. Есть только проблема - если вы давно не обновляли клиент, fingerprint его может устареть, отставая от актуальных версий браузеров (в некоторых странах так блокировали Cloak, использовавший TLS fingerprint какой-то старой версии Firefox), а во-вторых, даже если фингерпринт похож, все равно какие-то нюансы поведения могут различаться, и цензоры рано или поздно могут вас на этом подловить.
Вы возможно слышали про naiveproxy, разработчику которого в погоне за максимально похожим на "настоящий" TLS fingerprint'ом пришла гениальная идея просто взять часть кода настоящего браузера Chromium и использовать его для установления соединения. У XRay есть идея не хуже - он может использовать настоящий браузер целиком :) Работать оно будет только с websocket- или SplitHttp-транспортом, зато это прямо максимально аутентичная маскировка.
Использовать довольно просто. Конфигурируете XRay как обычно для вебсокетов или splithttp (можно создать подключение в Nekoray и экспортировать конфиг, чтобы проще было), а потом нужно запустить XRay с переменной окружения типа XRAY_BROWSER_DIALER=127.0.0.1:8080
. В Linux ее можно вставить сразу перед командой запуска xray, в Windows задать командой "set" перед запуском.
После этого открываете в браузере адрес http://127.0.0.1:8080 (выглядит оно как пустая страница), и XRay начинает использовать его как промежуточный пункт для соединения с удаленным прокси-сервером - вы можете увидеть в "Developer Tools -> Network" websocket-подключения парами, часть к локальному XRay, а часть к удаленному прокси-серверу.
Два важных нюанса: 1) в браузере, который вы используете как промежуточный транзит, не должно быть задано прокси в настройках (иначе запрос к удаленному прокси попадет снова на XRay, и получится бесконечный цикл); если вы используете TUN-интерфейс, то клиенты обычно делают исключение в маршрутах для адреса прокси назначения, но могут быть свои приколы. 2) количество одновременных вебсокет-подключений в браузере ограничено, поэтому рекомендуется использовать мультиплексирование (mux) в XRay. Между тем, ничто не запрещает открыть в браузере несколько вкладок, они будут использоваться для проксирования одновременно.
И наконец, не обязательно открывать окно браузера, Chrome можно запустить в headless mode (без видимого окна), например как-то так:
"c:Program FilesGoogleChromeApplicationchrome.exe" --headless=new --remote-debugging-port=0 --no-proxy-server http://127.0.0.1:8080/
Здесь одной командой мы запускаем его в headless-режиме, отправляя сразу на локальный адрес XRay, отключаем использование прокси, и включаем remote debugging, чтобы можно было проверить если что-то вдруг пойдет не так.
Автор: UranusExplorer