Fallbacks для VLESS и Trojan
Входящий VLESS или Trojan на обычном TCP-транспорте может делить порт с сайтом. После TLS слушатель читает первые байты потока. Если это не запрос одного из его пользователей, поток вместе с уже прочитанными байтами уходит на локальный сервер, например nginx. Браузер или сканер, открывший адрес, видит этот сайт, а не закрытое соединение.
Это опция fallbacks из Xray-core с теми же полями: name, alpn, path, dest и xver.
listeners: - name: vless-in type: vless port: 443 listen: 0.0.0.0 users: - { username: alice, uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68, flow: xtls-rprx-vision } certificate: /etc/citrus-server/fullchain.pem private-key: /etc/citrus-server/privkey.pem fallbacks: - dest: 8080 # всё остальное: 127.0.0.1:8080 - path: /api # GET /api?x HTTP/1.1 dest: 127.0.0.1:8081 xver: 1 # сначала заголовок PROXY protocol v1 - alpn: h2 # браузеры, договорившиеся о HTTP/2 dest: /run/nginx/h2.sock - name: blog.example.com # по SNI dest: 127.0.0.1:8082У Trojan такой же список.
Какие потоки уходят в fallback
Заголовок раздела «Какие потоки уходят в fallback»- VLESS: первый байт не версия 0 или следующий за ним UUID не принадлежит пользователю.
- Trojan: первые 56 байт не строчный hex с CRLF после него или ключ не принадлежит пользователю.
Неизвестный UUID или ключ, как и без fallbacks, попадает в события как неудачный вход. Если начало потока ещё может оказаться заголовком протокола, но поток обрывается раньше конца заголовка, он закрывается по сроку рукопожатия через 15 секунд и в fallback не уходит.
Слушатель читает столько, сколько нужно для решения: для большей части веб-трафика один байт, для VLESS 17 байт, для Trojan 58 байт. Если у какого-то fallback задан path, он дочитывает до конца пути, в пределах первых 256 байт. Заголовок может прийти в нескольких записях, если успевает до срока рукопожатия.
Сопоставление
Заголовок раздела «Сопоставление»| Поле | Сравнивается с | Пусто |
|---|---|---|
name |
SNI из TLS: само имя, иначе самый длинный name, который содержится в SNI, как в Xray. example.com подходит и для www.example.com (и для notexample.com). Регистр не важен, шаблонов нет. |
любое имя и отсутствие TLS |
alpn |
согласованный ALPN, например h2 или http/1.1 |
любой |
path |
путь из строки запроса HTTP/1.x: /api в GET /api?x HTTP/1.1. Начинается с /. У HTTP/2 нет строки запроса, поэтому path с h2 не совпадает |
любой |
Порядок в списке не важен. Fallback выбирается как в Xray: сначала name, внутри него alpn, затем path. Если совпадения нет, на каждом шаге берётся пустое значение. Fallback с name наследует пары alpn и path от fallback без name, если сам не задаёт такую же пару. Например, при {path: /ws, dest: 10001} и {name: blog.example.com, dest: 8082} запрос GET /ws с SNI blog.example.com уходит на 10001, а остальной трафик блога на 8082. Так же fallback с alpn наследует пути fallback без alpn с тем же name. Два fallback с одинаковыми name, alpn и path — ошибка конфига. Поток, который не совпал ни с одним fallback, закрывается. Для значения по умолчанию добавьте fallback только с dest.
Если хотя бы у одного fallback задан alpn, TLS предлагает перечисленные значения и http/1.1. Без alpn ALPN не согласуется, как и раньше. Клиент, который предлагает только ALPN вне этого списка, не пройдёт рукопожатие. Клиент с http/1.1 или вообще без ALPN подключится. Стандартный для Trojan h2, http/1.1 тоже работает.
Назначение
Заголовок раздела «Назначение»dest:8080(порт на 127.0.0.1),host:portили unix-сокет:/run/web.sock,@name(abstract, Linux) илиunix:C:\web.sock.xver: 1или2: сначала отправить заголовок PROXY protocol этой версии с адресом и портом клиента и адресом слушателя. Если у входящего включёнproxy-protocol, в заголовок идёт адрес из заголовка фронтенда. Адрес клиента не IP (например, у слушателя на unix-сокете) уходит какUNKNOWN(v1) или неуказанный адрес (v2). nginx читает заголовок сlisten ... proxy_protocol.
Подключение к dest идёт напрямую, мимо правил. Предполагается, что это локальный адрес. Таймаут подключения — 5 секунд.
Ограничения
Заголовок раздела «Ограничения»Как в Xray, у ретрансляций fallback нет лимита на число и таймаута простоя. Через них идут сайт и входящие, подключённые через path, например ws, а такие сессии могут подолгу молчать. Лимиты задаются на сервере в dest, например через limit_conn и keepalive_timeout в nginx. Закрытие слушателя закрывает его ретрансляции.
Если dest недоступен, первая ошибка пишется в лог как предупреждение, дальше не чаще одного предупреждения в минуту. Остальные ошибки уходят в debug-лог: вызвать такую ошибку может любой клиент.
Где работает
Заголовок раздела «Где работает»- Только на обычном TCP-транспорте.
fallbacksвместе сws-path,grpc-service-nameилиxhttp-config— ошибка конфига. На этих HTTP-транспортах чужие запросы обслуживаетfallback-page. - С любым слоем безопасности: TLS (
certificate), REALITY, ShadowTLS, JLS, ResTLS или без него сallow-insecure.nameработает с TLS и REALITY,alpnтолько с TLS: REALITY не согласует ALPN, поэтому за ним совпадает только пустойalpn. За остальными слоями оба поля пусты и совпадают только с пустыми значениями. - Не работает с
decryptionу VLESS иss-optionу Trojan: там заголовок зашифрован, и fallback получил бы шифротекст. Оба сочетания — ошибка конфига.
fallback-page
Заголовок раздела «fallback-page»fallback-page — статическая HTML-страница для ws, grpc и xhttp. Её отдаёт тот же HTTP-сервер на запросы, которые не относятся к входящему. Она и fallbacks никогда не обслуживают одно соединение. С fallbacks транспорт — обычный TCP, а там fallback-page не действует. Если заданы оба, слушатель пишет предупреждение в лог.
