XHTTP: Beyond REALITY #4113
Replies: 61 comments 245 replies
-
先顶再看,不明觉厉 |
Beta Was this translation helpful? Give feedback.
-
中文 | РусскийUPDATED 11.03.2025 XHTTP: За гранью REALITYКраткое описание разработки: В середине 2024 года, @mmmray @ll11l1lIllIl1lll и другие, основываясь на принципе "раздельная пакетная отправка, потоковая загрузка" и деталях реализации, описанных @RPRX, разработали SplitHTTP, впервые добившись обхода большинства промежуточных устройств, поддерживающих HTTP, без ущерба для эффективности загрузки, и впервые массово реализовали QUIC H3 через CDN, открыв новую эру. Впоследствии были реализованы: Broswer Dialer, добавление отступов в заголовки для уменьшения сигнатуры (header padding), управление мультиплексированием (XMUX) и разблокировка REALITY. Затем разработку взял на себя @RPRX, реализовав настоящее разделение исходящего и входящего трафика и переименовав проект в XHTTP. Например, исходящий и входящий трафик могут быть IPv6 CDN H3 и IPv4 REALITY H2 соответственно (даже исходные IP-адреса могут различаться), Эта статья призвана помочь вам полностью понять принцип и дизайн XHTTP, чтобы вы могли лучше его использовать. Если вы хотите пожертвовать проекту Xray или собираете NFT, соответствующая информация находится в конце статьи, спасибо за поддержку!Руководство по быстрому стартуНесмотря на большое количество параметров XHTTP, большинство из них имеют значения по умолчанию. Если вы просто хотите использовать XHTTP, следуйте этим шести шагам:
XHTTP по умолчанию использует мультиплексирование, что обеспечивает меньшую задержку, чем у Vision, но тесты скорости показывают худшие результаты, если не установлено CF обрывает HTTP-соединения без передачи данных в течение 100 секунд. Для поддержания активности долговременных соединений через прокси необходимо реализовать keep-alive на уровне приложения. Например, для SSH необходимо установить Эта статья может служить расширенной документацией. Она охватывает практически все, что вы хотите знать о XHTTP, с объяснением каждого параметра. В конце статьи приведен пример конфигурации со всеми параметрами и описанием сценариев их использования. Если вам неясен какой-либо параметр, найдите его имя в тексте, чтобы найти подробное объяснение. Два базовых принципаТак же, как REALITY может маскироваться под чужой веб-сайт, фундаментальная логика борьбы с цензурой заключается в увеличении «сопутствующего ущерба» для цензоров при блокировке, чтобы они не решались легко блокировать. Я в свое время делал ставку на TLS и запутывание временных и размерных характеристик трафика TLS по той же причине. Многолетний опыт показывает нам, что GFW не будет навсегда блокировать весь IP-адрес крупного CDN, иначе это затронет слишком много обычных веб-сайтов. Таким образом, для XHTTP наша первоначальная цель состояла в том, чтобы скрыть его за множеством различных CDN. Однако CDN, чтобы предотвратить атаки на исходный сервер, обычно кэшируют весь HTTP-запрос, прежде чем отправлять его на исходный сервер, за исключением специально поддерживаемых WS и gRPC. Многие промежуточные HTTP-устройства по умолчанию ведут себя аналогичным образом. Исходя из этого, протокол Meek от Tor упаковывает исходящий и входящий трафик в отдельные HTTP-запросы для обхода этих промежуточных устройств, но скорость ужасно низкая, потому что он не использует «потоковую загрузку» XHTTP. Что такое «потоковая загрузка»? Представьте, что вы загружаете большой файл с веб-сайта, и CDN не находит его в кэше, поэтому обращается к исходному серверу. Но, очевидно, он не будет кэшировать весь файл, как при загрузке, заставляя вас ждать, а будет немедленно передавать вам данные по мере их получения от исходного сервера. Это основа «потоковой загрузки» XHTTP, которая также гарантирует максимальную скорость загрузки. Что касается загрузки, то из соображений совместимости XHTTP сначала реализовал «пакетную загрузку», то есть упаковку исходящего трафика в отдельные POST-запросы. Его эффективность, очевидно, снижается, но, к счастью, для обычных прокси-серверов объем исходящего трафика очень мал. Позже я добавил «потоковую загрузку», и мы обнаружили, что с добавлением маскировки заголовка gRPC можно использовать потоковую загрузку H2 через CF, а после нескольких раундов оптимизации «пакетной загрузки» скорость даже приблизилась к «потоковой загрузке». Кстати, о недавно ставшем популярным вопросе об «злоупотреблении» CDN: очевидно, что CDN, не поддерживающие потоковую загрузку, не предназначены для создания прокси-сервисов. Но для борьбы с GFW мы должны постоянно исследовать, разрабатывать и использовать как можно больше новых путей. Это разумно и необходимо, это вынужденная мера, и увеличение «сопутствующего ущерба» для цензоров требует от нас смешиваться с «нормальными» сервисами, что также неизбежно. Простейший пример: если в один прекрасный день будет введен белый список IP-адресов, и IP-адрес CDN окажется в нем, будете ли вы его использовать? В области борьбы с цензурой не применяются некоторые правила реального мира, но этот простой принцип многие до сих пор не понимают. Если вы все еще не поняли, то такой транспортный уровень, как WebSocket, сейчас существует только для обхода CDN. Как разработчик, вы можете удалить его, как пользователь, вы можете предложить разработчику удалить его, чтобы своими действиями доказать, что «злоупотребление CDN» — это не просто завистливая атака на Xray, которая является еще одним предлогом для удовлетворения нездоровой психологии, в то же время нетрудно заметить, что лицемерная сущность некоторых людей полностью раскрыта. PACKET-UPЭтот раздел содержит много технических деталей. Обычные пользователи могут прочитать только выделенный текст. Для режима packet-up, обеспечивающего максимальную совместимость XHTTP («пакетная загрузка, потоковая выгрузка»), мы использовали следующую схему:
Пакетная загрузка и Кроме того, как и другие транспортные уровни Xray, сервер принимает заголовок Это упрощенный, необходимый процесс для режима packet-up. Однако остается один вопрос: как конкретно реализовать и ограничить POST-запросы? Для этого есть три специальных параметра:
«Для одного прокси-запроса» означает, что каждый прокси-запрос имеет свой счетчик и не влияет на другие, даже если они находятся в одном H2/H3 соединении. Это значение sc, то есть sub-connection. Чтобы уменьшить отпечаток, первые два значения можно задать в виде диапазона, например, "500000-1000000" и "10-50" соответственно, со случайным выбором значения для каждого запроса. Эти параметры можно передать клиенту через H1 / H2 / H3Раз уж у нас есть режим packet-up, способный проходить практически через все промежуточные устройства, давайте обсудим кое-что интересное: QUIC H3 через CDN, то есть начало новой эры SplitHTTP. Понимание этого раздела особенно важно для гибкого использования XHTTP. Особенностью многих HTTP-посредников, таких как CDN и Nginx, является преобразование версии HTTP. Например, они могут преобразовывать входящий трафик H3 в H1 или H2 при обращении к исходному серверу. Это означает, что наш сервер XHTTP может прослушивать только H1 и H2, без необходимости прослушивания H3, в то время как клиент XHTTP может использовать H3. Это поведение по умолчанию для сервера XHTTP: прослушивание только TCP-порта и обработка трафика H1 и H2. При включении TLS и указании только "h3" в Для клиента XHTTP:
Если вам нужно узнать фактическую версию HTTP, используемую клиентом Xray, host, а также режим XHTTP, разделение загрузки и выгрузки и другую информацию, установите уровень ведения журнала "info". Проксирование QUIC H3 через CDN, по крайней мере, XHTTP был первым, кто реализовал это в больших масштабах, открыв новый путь, ведь в некоторых регионах и у некоторых операторов связи цензура H3 не так строга, XMUXРаз уж мы упомянули H2 и H3, нельзя не упомянуть их мультиплексирование: оба имеют 0-RTT. Разница в том, что у H3 нет проблемы блокировки головки TCP, как у H2, и он поддерживает миграцию соединения, поэтому переключение сети на стороне клиента не приведет к разрыву соединения.
Параметры XMUX можно комбинировать различными способами. Например, для многопоточного тестирования скорости необходимо установить Примечание: отсутствие значений эквивалентно нулевым значениям, будут использованы три значения по умолчанию. Но если указан хотя бы один параметр, остальные параметры не имеют значений по умолчанию и должны быть указаны явно, за исключением первых двух параметров. Все остальные параметры можно указывать одновременно. Кроме того, при использовании XHTTP не следует включать mux.cool. Новая версия сервера Xray имеет проверку и принимает только чистый XUDP. Некоторые выдержки о значениях по умолчанию XMUX:
Далее в статье обсуждаются некоторые параметры Nginx. STREAM-UP/ONEНаконец, очередь дошла до другого важного режима XHTTP: "потоковая загрузка, потоковая выгрузка" (stream-up). Как следует из названия, в этом режиме загрузка также является потоковой, что не снижает ее эффективность. Он был первоначально разработан для REALITY, пока мы не обнаружили, что маскировка заголовка gRPC под H2 позволяет проходить через CF (необходимо включить поддержку gRPC в панели управления), и обратные прокси-серверы, такие как Nginx, также хорошо его поддерживают (для Nginx рекомендуется grpc_pass, это просто и удобно). Поэтому поведение
Способы их реализации (не разработчики могут пропустить):
Тогда те, кто часто использует gRPC, спросят: какие преимущества имеет stream-up по сравнению с транспортным уровнем gRPC?
Конечно, преимущества XHTTP по сравнению с WebSocket и HTTPUpgrade, помимо «отсутствия явного признака ALPN как http/1.1», вы, дочитав до этого места, уже наверняка поняли сами, и я не буду их перечислять, Разделение загрузки и выгрузкиИ, наконец, еще одна новая эра: разделение загрузки и выгрузки. Мы примерно знаем, что сейчас GFW обнаруживает такие характеристики трафика, как TLS in TLS, на основе одного соединения. Таким образом, если мы разделим загрузку и выгрузку на разные соединения, например, загрузка будет идти по TCP через IPv4, а выгрузка — по UDP через IPv6, GFW не сразу сможет сориентироваться. А поскольку сервер XHTTP связывает загрузку и выгрузку только на основе случайно сгенерированного UUID в пути, packet-up и stream-up изначально обладают настоящей способностью разделять загрузку и выгрузку. И поскольку XHTTP может проходить через различные CDN, может сочетаться с REALITY и другими технологиями, количество возможных вариантов бесконечно. Для клиента необходимо настроить "xhttpSettings": {
"host": "example.com",
"path": "/yourpath", // должен быть одинаковым
"mode": "auto",
"extra": {
"headers": {
// "key": "value"
},
"xPaddingBytes": "100-1000",
"noGRPCHeader": false, // stream-up/one, только клиент
"noSSEHeader": false, // только сервер
"scMaxEachPostBytes": 1000000, // только packet-up
"scMinPostsIntervalMs": 30, // packet-up, только клиент
"scMaxBufferedPosts": 30, // packet-up, только сервер
"scStreamUpServerSecs": "20-80", // stream-up, только сервер
"xmux": { // в основном h2/h3, только клиент
"maxConcurrency": "16-32",
"maxConnections": 0,
"cMaxReuseTimes": 0,
"hMaxRequestTimes": "600-900",
"hMaxReusableSecs": "1800-3000",
"hKeepAlivePeriod": 0
},
"downloadSettings": { // только клиент
"address": "", // другой домен/IP
"port": 443,
"network": "xhttp",
"security": "tls",
"tlsSettings": {
...
},
"xhttpSettings": {
"path": "/yourpath", // должен быть одинаковым
...
},
"sockopt": {} // будет заменено на "sockopt", если в последнем "penetrate" равно true
}
}
} Как видно, На самом деле, если вы используете CDN, вы можете использовать разделение загрузки и выгрузки, даже не изменяя конфигурацию сервера. Например, вы можете выбрать IPv4 для TLS H2 и IPv6 для QUIC H3. Кроме того, CDN обычно поддерживают «префикс одного домена». Например, Например, после появления разделения загрузки и выгрузки многие используют его для разделения загрузки на канал с лучшим исходящим трафиком, а выгрузки — на канал с лучшим входящим трафиком, что также довольно практично. Например, вы можете установить Выше приведен пример конфигурации со всеми параметрами, главным образом для того, чтобы показать, где должен быть каждый параметр, и объяснить параметры, которые не были подробно рассмотрены в тексте:
Beyond REALITYВ начале прошлого года я вернулся и написал REALITY, одним махом решив несколько проблем, Beyond REALITY означает не замену REALITY, а превзойдение REALITY по популярности. Без преувеличения, как это всегда было в стиле Xray, появление XHTTP затмевает все другие транспортные уровни на основе HTTP. Это эпоха всеобщего господства XHTTP. Он станет более популярным, чем предыдущий успешный протокол REALITY, потому что характеристики XHTTP уже определяют его более широкое применение. Наконец, надеюсь, что появление XHTTP немного потрясет всех, как это неоднократно делал Xray в своей истории: инновации и постоянное обновление — это кредо Xray. Если эта статья была вам полезна, поддержите REALITY NFT:
Благодаря вашей поддержке, Project X NFT вырос в пять-шесть раз. Для тех, кто выжидал во время первого выпуска Project X NFT, это хороший шанс наверстать упущенное. Конечно, если у вас есть возможность, мы будем еще более благодарны за поддержку Project X NFT:
|
Beta Was this translation helpful? Give feedback.
-
It's rumored that some CDNs are acting against using their services for proxy (not at a large scale yet) As someone who don't want to get banned by CDNs, i prefer WebSocket or gRPC w/o '/Tun', but not XHTTP with static URL Pattern and xPaddingBytes query string with many 0 data |
Beta Was this translation helpful? Give feedback.
-
笔记本上:嗯嗯嗯,好好好,嗯嗯嗯,好好好,嗯嗯嗯,好好好 |
Beta Was this translation helpful? Give feedback.
-
Six,Six,Six... |
Beta Was this translation helpful? Give feedback.
-
尝试过
|
Beta Was this translation helpful? Give feedback.
-
奈何本人没文化,一句牛逼行天下🥰 |
Beta Was this translation helpful? Give feedback.
-
建议文中优化下"extra"的说明: 对于mode配置,也建议文中增加链接: 如果正文没修改,读者对extra或mode有疑问,可以读这个回复里的链接 |
Beta Was this translation helpful? Give feedback.
-
这种配置算“关闭了mux.cool(我理解是tcp的mux)纯xudp”吗?如果不是最佳实践 应该是怎样 |
Beta Was this translation helpful? Give feedback.
-
Look good to all |
Beta Was this translation helpful? Give feedback.
-
可否考虑在跑H3时,配置启用了cMaxLifetimeMs连接过期时间参数后,能把过期的主连接中的子连接迁移到新连接中,这样规避对UDP的Qos。 |
Beta Was this translation helpful? Give feedback.
-
尝试理解下我们XTLS旗下一系列协议的关注点和逻辑,如果错了请 @RPRX 指正。 XTLS初代splice/direct/origin等----解决性能: VISION----解决TLS in TLS特征: REALITY----解决SNI封锁问题: XHTTP----解决翻墙协议普遍存在的“单一隧道”特征: |
Beta Was this translation helpful? Give feedback.
-
![]() stream-up performance is much better. But it has a long way to reach tcp reality xtls-rprx-vision. |
Beta Was this translation helpful? Give feedback.
-
cloudfront可以用吗 |
Beta Was this translation helpful? Give feedback.
-
XHTTP 能用 xray 自己做接入层吗,不用CDN的情况下。还是必须nginx? 比如以下设想 Client -> up -> REALITY+XHTTP -> node2 -> VMESS/RAW -> node1 |
Beta Was this translation helpful? Give feedback.
-
请问一下xhttp的reality设置里面的dest是什么时候改成target的 |
Beta Was this translation helpful? Give feedback.
-
@RPRX I had a question : Doesn't xray round robin load balancing with multiple links perform a similar function to download/upload separations in xhttp? Because I see countless similarities between xhttp upload/download separation and load balancer. |
Beta Was this translation helpful? Give feedback.
-
经实验,部分CDN不支持流式下行,无论是否关闭缓存(例如 Azure CDN Standard 会直接卡住,直到超时)。想问能否考虑提供分包下行的降级机制,以便在特殊情况下保留高兼容性的保底手段? |
Beta Was this translation helpful? Give feedback.
-
In packet-up mode, when alpn is set to http/1.1, it displays the following error transport/internet/splithttp: failed to GET https:// example . com /path/7c40dcf9-f713-4007-a85b-b786dfa7895f?x_padding=000 > Get "https:// example . com /path/7c40dcf9-f713-4007-a85b-b786dfa7895f?x_padding=000": net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x00\x00\x12\x04\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x80\x00\x04\x00\x01\x00\x00\x00\x05\x00\xff\xff\xff\x00\x00\x04\b\x00\x00\x00\x00\x00\x7f\xff\x00\x00\x00\x00\b\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" |
Beta Was this translation helpful? Give feedback.
-
Greetings to all core developers except @RPRX. This person is an example of a violation of personal privacy, as they published a text and made a serious accusation against the developer of @3X-UI. Meanwhile, based on my usage and that of my friends in Iran, China, and Russia, 3X-UI is the most complete panel available. Due to their extremely inappropriate behavior in this matter, I request an apology from them on behalf of this entire community. If they fail to apologize, I call upon the great communities of China, Russia, and Iran to boycott RPRX. We have grown up under authoritarian governments, but we will not allow an individual in this community to insult and accuse others. Power does not belong to a single person—you are not in control. Do not forget that. |
Beta Was this translation helpful? Give feedback.
-
after upgrading from 25.1.1 to 25.1.30 stream-up with CF stopped working, packer-up running normal. Is it only for me? |
Beta Was this translation helpful? Give feedback.
-
@RPRX REALITY Vision 回落 XHTTP 应用使用 UDS 连接,服务端与客户端都 v25.1.1 升级为 v25.1.30 后,原正常的 REALITY XHTTP 应用无法使用(连接测试超时)。 |
Beta Was this translation helpful? Give feedback.
-
Do I need add this option: "scStreamUpServerSecs": "20-80" to my server config.json or not? |
Beta Was this translation helpful? Give feedback.
-
I'm still confused about stream-up and stream-one what are the differences? Which one should I use with TLS XHTTP3? |
Beta Was this translation helpful? Give feedback.
-
因为找了一个略微丢包(2%左右)的vps,于是尝试xhttp+h3看看走udp的话能不能让连接状况好一些,不过发现了难受的地方,不知是nginx的问题还是xray的问题(或是vps的?) 暂时没有更多的时间来测试,等忙完周末再看看 |
Beta Was this translation helpful? Give feedback.
-
我正在用谷歌翻译用中文写文章。如果我的文字不正确,请原谅。 上下文 | Context最近,我开始测试 XHTTP+TLS+CDN,同时考虑放弃旧的 REALITY 设置。这是为了实现更好的可靠性(nginx+CDN)、速度(HTTP3)并使用 subscriptions。但你可以说主要目标是 HTTP3。 我听说 HTTP3 在处理不稳定的互联网连接方面略胜一筹。虽然有线互联网通常提供稳定的连接,没有数据包丢失,但移动互联网并非如此。在农村或地下地区,或在高峰时段,当 4G 连接峰值速度不超过每秒 2 兆比特时,RTT 可能会从平均 150 毫秒随机飙升至 1100 毫秒。在这种情况下,HTTP2 Head-of-line blocking 可能成为一个问题。如果 HTTP3 可以改善这种情况,那么它值得一试。 问题描述 | Problem description虽然 BEYOND REALITY 中没有明确说明这一点,但我认为 h3 不适用于 stream 模式,所以当我提到 h3 时,我指的是 packet-up 模式。 我从 #4118 中获取了配置文件。经过一些故障排除(#4478)后,它工作正常,但 packet-up 模式下的 h3 在使用一段时间后性能不佳。它一开始工作正常,但随后速度减慢到固定速度,或完全停止。它似乎……拥塞?受限?packet-up 和 stream-one 模式下的 h2 工作正常,没有这样的问题。 我将使用 Youtube 进行演示,但这可能发生在任何网站上,随时。当你在 Youtube 视频中跳转太多时,你的下载速度会下降到某个固定值,或者如果你跳转过度,则会降至 0。它会保持不变。如果你暂停视频足够长的时间或重新加载 V2RayN,拥塞就会消失。虽然这种状态是由我对 Youtube 的操作引起的,但它是自发发生的,并影响整个互联网连接。一切都变慢或停止工作,甚至 domain resolving。Connection Timeout、context deadline exceeded、EOF。 我认为这是因为 V2RayN -> CloudFlare -> VPS 链的请求太多,无法处理,所以我向下滚动 Youtube 搜索网页,试图对其进行 DDOS,但什么也没发生。我还下载了 800MB file,并没有发生拥塞。似乎不是由流量大小引起的。 我将附上版本、日志和演示此问题的视频示例。您可以看到速度从自然的 50 兆比特下降到人为的 8 兆比特。我没有按太多,所以互联网连接保持工作状态。 example.mp4这个问题在 V2RayNG 上比 V2RayN 更严重。它经常自发发生,不需要我手动触发。一切都突然停止或减慢太多。网站组件加载速度有限,网页被剥离 CSS 并变成 WEB 1.0。不幸的是,我无法提供 V2RayNG 日志,因为 P.S. 我想尝试上下行分离,但 V2RayN 在恢复备份时似乎会忽略客户端配置。我不知道如何将其输入到 P.P.S 在我重现拥堵以收集日志并将速度降至零后,拥堵在大约五分钟后自行缓解。我再次重现拥堵,这次既没有缓解拥堵,也没有 V2RayN 重新加载帮助。我切换到 h2,它起作用了。 程序版本 | VersionsXray 25.3.6 Debian 12 VPS, IPv4+IPv6 V2RayN 7.10.5 Xray error.log normal[Warning] core: Xray 25.3.6 started Xray error.log congested2025/03/20 10:02:22.169047 [Warning] core: Xray 25.3.6 started . . . 2025/03/20 10:03:10.833286 [Info] [3537200014] app/proxyman/inbound: connection ends > proxy/vless/inbound: connection ends > context canceled V2RayN log. . . [Info] proxy/vless/outbound: tunneling request to udp:1.1.1.1:53 via CF CDN IP[Info] [3245867330] app/proxyman/inbound: connection ends > proxy/http: connection ends > context canceled [Info] app/dns: failed to lookup ip for domain www.youtube.com at server DOH//dns.google > context deadline exceeded Info] features/routing/dns: resolve ip for www.youtube.com > app/dns: returning nil for domain www.youtube.com > multierr: context deadline exceeded | context deadline exceeded | context deadline exceeded | [Info] [1117263667] app/dispatcher: taking detour [proxy] for [tcp:www.youtube.com:443] [Error] app/dns: failed to retrieve response for www.youtube.com. > Post "https://dns.google/dns-query": context deadline exceeded [Info] [1117263667] transport/internet/splithttp: XHTTP is dialing to udp:CF CDN IP, mode packet-up, HTTP version 3, host b.my.site [Error] app/dns: failed to retrieve response for www.youtube.com. > Post "https://dns.google/dns-query": context deadline exceeded from 127.0.0.1:4032 accepted //www.youtube.com:443 [socks -> proxy] from DNS accepted https://dns.google/dns-query [xray.system.dd05e727-9e13-4286-8623-ce74efb9d867 -> proxy] [Info] app/dispatcher: taking detour [proxy] for [tcp:dns.google:443] [Info] [1117263667] proxy/vless/outbound: tunneling request to tcp:www.youtube.com:443 via CF CDN IP [Info] transport/internet/splithttp: XHTTP is dialing to udp:CF CDN IP, mode packet-up, HTTP version 3, host b.my.site [Info] proxy/vless/outbound: tunneling request to tcp:dns.google:443 via CF CDN IP [Error] app/dns: failed to retrieve response for alive.github.com. > Post "https://dns.google/dns-query": context deadline exceeded [Info] app/dispatcher: taking detour [proxy] for [tcp:dns.google:443] from DNS accepted https://dns.google/dns-query [xray.system.dd05e727-9e13-4286-8623-ce74efb9d867 -> proxy] [Info] transport/internet/splithttp: XHTTP is dialing to udp:CF CDN IP, mode packet-up, HTTP version 3, host b.my.site [Info] proxy/vless/outbound: tunneling request to tcp:dns.google:443 via CF CDN IP [Info] [2432620260] app/proxyman/inbound: connection ends > proxy/http: connection ends > context canceled [Info] app/dns: failed to lookup ip for domain alive.github.com at server UDP:1.1.1.1:53 > context deadline exceeded [Debug] app/dns: UDP:8.8.8.8:53 querying DNS for: alive.github.com. [Info] transport/internet/udp: establishing new connection for udp:8.8.8.8:53 [Debug] transport/internet/udp: dispatch request to: udp:8.8.8.8:53 [Info] app/dispatcher: taking detour [proxy] for [udp:8.8.8.8:53] from DNS accepted udp:8.8.8.8:53 [xray.system.dd05e727-9e13-4286-8623-ce74efb9d867 -> proxy] [Info] transport/internet/splithttp: XHTTP is dialing to udp:CF CDN IP, mode packet-up, HTTP version 3, host b.my.site [Info] proxy/vless/outbound: tunneling request to udp:8.8.8.8:53 via CF CDN IP [Info] app/dns: failed to lookup ip for domain alive.github.com at server UDP:8.8.8.8:53 > context deadline exceeded . . . [Debug] transport/internet/udp: dispatch request to: udp:1.1.1.1:53 [Debug] transport/internet/udp: dispatch request to: udp:1.1.1.1:53 [Info] [1757992469] app/proxyman/outbound: app/proxyman/outbound: failed to process outbound traffic > proxy/vless/outbound: connection ends > proxy/vless/outbound: failed to transfer response payload > H3_MESSAGE_ERROR [Info] [1757992469] app/proxyman/inbound: connection ends > proxy/http: connection ends > io: read/write on closed pipe [Info] [3057622213] app/proxyman/inbound: connection ends > proxy/http: connection ends > context canceled . . . access_xhttp.log. . ."POST b.my.site/MY PATH/6fff4591-6140-4a0c-a62d-9a3f4700096e/0 HTTP/2.0" 200 0B "b.my.site" "quic-go HTTP/3" 0.002ms 0.003ms . . . |
Beta Was this translation helpful? Give feedback.
-
中文 | Русский
XHTTP: Beyond REALITY
开发简述:2024 年中,@mmmray @ll11l1lIllIl1lll 等人基于 @RPRX 所述的“分包上行、流式下行”原理及实现细节开发出了 SplitHTTP,首次实现了不牺牲下行效率的同时穿透绝大多数支持 HTTP 的中间盒,并首次大规模实现了 QUIC H3 过 CDN,开启了一个崭新的时代,浏览器转发 Broswer Dialer 支持、减少特征的 header padding、控制复用的 XMUX、解锁 REALITY 也相继被安排上。随后 @RPRX 接手开发,实现了真正的上下行分离并更名为 XHTTP,比如上下行可以分别是 IPv6 CDN H3、IPv4 REALITY H2(源 IP 都可以不同),
这下又开启了一个崭新的时代,紧接着开发了不牺牲上行效率的流式上行 stream-up 模式、可以分享全部细节配置的 extra 方案,并给 stream-up 模式加上了默认的 gRPC header 伪装,实现了 H2 流式上行过 CDN,取代了传统的 gRPC 传输层,当初发现这也行就不会有它了,最后将 HTTP 传输层作为 stream-one 模式并入 XHTTP,使其也拥有了 header padding、XMUX、gRPC header 伪装等特性。至此,我们有了完全体 XHTTP:各种姿势穿透中间盒、上下行分离、丝滑的 XMUX 等应有尽有,XHTTP 全场景通吃的时代正式到来。原为导剪版文档,不小心写成了文章。这篇文章旨在帮助你透彻地理解 XHTTP 的原理、设计,以便更好地使用它。
如果你要捐助 Xray 项目、收藏 NFT,相关介绍在文末,感谢支持!
快速上手指南
别看 XHTTP 的参数较多,其实都调好了默认值,如果你只是想用 XHTTP 的话,只需遵循六步:
path
,其它不填即可alpn
选 "h3" 即可使用 QUICaddress
填 IP,serverName
(SNI)填域名即可mode
选 "packet-up",兼容性最强XHTTP 默认有多路复用,延迟比 Vision 低但多线程测速不如它,除非测速前设了
"maxConcurrency": 1
,参考 XMUX 小节。CF 会掐断下行 100 秒无实际数据的 HTTP,代理长连接需在应用层面保活,比如 SSH 需在 sshd 设置
ClientAliveInterval
。这篇文章可以当增强版文档用,它基本上涵盖了关于 XHTTP 你想要了解的所有内容,对每个参数都有解释,文末也有一份涵盖了所有参数的配置示例,并且标注了每个参数的使用场景,如果你对哪个参数不清楚,文内搜索参数名即可找到该参数的详细解释。
两个底层逻辑
正如 REALITY 可以伪装成别人的网站,反审查的根本逻辑就是增加审查者执行封锁时的“附带伤害”,使审查者不敢贸然封锁,我当年看好 TLS 以及 TLS 上流量的时序、长度特征混淆也是同理。多年经验告诉我们 GFW 不会永久封锁大型 CDN 的整个 IP,否则会波及太多常规网站,那么对于 XHTTP,我们最初的目标就是把它隐藏在众多各种各样的 CDN 后面。然而 CDN 为了防止源站遭受攻击,除了有特殊支持的 WS、gRPC 外,一般会缓存完整个 HTTP 请求再发给源站,许多 HTTP 中间盒默认也是这样的行为。据此,Tor 的 Meek 协议把往返流量包装为了一个个 HTTP 请求以穿透这些中间盒,但速率惨不忍睹,因为它没有采用 XHTTP 的“流式下行”。什么是“流式下行”呢?想象一下你正在一个网站上下载一个很大的文件,CDN 没击中缓存于是回源拿,但显然它不太好像上行一样先缓存完整个文件让你干等,而是源站发来多少数据,CDN 就即时转发给你,这就是 XHTTP “流式下行”的基础,也保证了最重要的下行速率可以拉满。至于上行,出于兼容性考虑,XHTTP 首先实现的是“分包上行”,即把上行流量包装为一个个 POST 请求,它的效率显然会打折扣,但好在对于一般的代理需求而言上行流量极少。此后我加了“流式上行”,并且我们发现加上 gRPC header 伪装后还能 H2 流式上行穿透 CF,而我几轮优化”分包上行“后速率甚至直追”流式上行“。
顺便谈一下最近又比较火的套 CDN 是否属于“滥用”的问题:显然不支持流式上行的 CDN 其本意并非让你用来搭建代理服务,但我们为了对抗 GFW,不断探索、开发、利用尽可能多的新路是合理且必要的,是不得已而为之,且增加审查者的“附带伤害”就是要求我们混入“正常”服务,这也是不可避免的。举个最简单的例子:哪天 IP 白名单了而 CDN 的 IP 在里面,你用还是不用?反审查这一领域并不适用现实世界的一些规则,这么简单的道理却一直都有人想不明白。 如果还是没想通,那像 WebSocket 这样的传输层现在仅为了套 CDN 而存在,作为开发者可以删掉它,作为用户可以建议开发者删掉它,以自身的实际行动来证明“滥用 CDN”并不只是为了眼红攻击 Xray 这一为满足某些病态心理的日经无聊行为而找出的又一个借口罢了,
与此同时身体却很诚实,与此同时不难窥见,有些人的虚伪本质已经暴露无遗。PACKET-UP
这一小节技术细节太多,非开发者可以只看粗体部分。
对于 XHTTP 兼容性最强的“分包上行、流式下行”,即 packet-up 模式,我们是这样设计的:
客户端
POST /yourpath/sameUUID/seq
以发送上行数据:客户端
GET /yourpath/sameUUID
启动下行,服务端响应头包含:X-Accel-Buffering: no
以告知中间盒禁用缓冲Cache-Control: no-store
以告知中间盒无需缓存Content-Type: text/event-stream
以伪装成 server-sent events(兼容性更好,可以设置noSSEHeader
以关闭)Transfer-Encoding: chunked
,H2/H3 则不需要为了避免浏览器转发 Browser Dialer 遇到跨域限制,服务端针对所有 GET、POST 的响应头都会包含:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST
为了解决 HTTP 请求头和响应头的固定长度特征:
Referer: ...?x_padding=XXX...
(放 Referer 是为了防止 Browser Dialer 产生不必要的 OPTIONS 请求),默认长度为 100-1000,每次请求随机,服务端默认会检查它是否在服务端允许的范围内X-Padding: XXX...
,默认长度为 100-1000,每次响应随机xPaddingBytes
Referer
由 @rPDmYQ 提出,选用XXX
也是,X
在 huffman encoding 中为 8 bit分包上行、
Referer: ...?x_padding=XXX...
会产生较多、较长的日志,你可以在反代软件中设置不记录它们。此外,和 Xray 的其它传输层一样,服务端也接受
X-Forwarded-For
header 以取得客户端的真实 IP,也会依据服务端设置的host
来检查客户端发来的 host(个人建议是没事别设,毕竟已经隐藏在 path 后面了)。以上就是 packet-up 模式的最简化、必要流程,不过此时还有个小问题:如何具体实施、限制 POST 请求?有三个专属参数:
scMaxEachPostBytes
:客户端每个 POST 最多携带多少数据,默认值 1000000 即 1MB,该值应小于 CDN 等 HTTP 中间盒所允许的最大值,服务端也会拒绝大于该值的 POSTscMinPostsIntervalMs
:仅客户端,基于单个代理请求,客户端发起 POST 请求的最小间隔,默认值 30 毫秒scMaxBufferedPosts
:仅服务端,基于单个代理请求,服务端最多缓存多少个 POST 请求,默认值 30 个,超限断连“基于单个代理请求”的意思是每个代理请求各自计数、互不影响,即使它们在同一条 H2 / H3 连接内,这便是 sc 即 sub-connection 的含义。为了减少指纹,前两个值可以设为范围的形式,比如分别为字符串 "500000-1000000"、"10-50",每次随机。这些参数都可以通过
extra
下发给客户端,文末有说明。此外值得一提的是,Xray 最新版优化了 packet-up,速率甚至直追 stream-up,主要利好 QUIC H3 过 CDN。H1 / H2 / H3
既然我们有了几乎能穿透所有 HTTP 中间盒的 packet-up 模式,让我们来讨论一个有趣的东西:QUIC H3 过 CDN,即当初 SplitHTTP 那个崭新的时代,理解这一小节对于灵活使用 XHTTP 尤为重要。
很多 HTTP 中间盒的一个特性就是会进行 HTTP 版本的转换,比如 CDN、Nginx 会将收到的 H3 流量转为 H1 或 H2 流量回源,也就是说我们的 XHTTP 服务端可以仅监听 H1 和 H2,无需监听 H3,但 XHTTP 客户端却可以使用 H3。
这也是 XHTTP 服务端的默认行为:仅监听 TCP 端口并处理 H1 和 H2 流量。 当启用 TLS 并在
alpn
处仅设置一个元素 "h3" 时,服务端将仅使用 quic-go 监听 UDP 端口并处理 H3 流量,但是目前不建议你这样做,而应将 XHTTP 隐藏在真正的 Nginx、Caddy 后面以减少指纹特征,这也是 XHTTP 相较于其它 QUIC 类代理的重要优点之一,另一个当然是能过 CDN。 此外 H3 的拥塞控制为应用层实现,理论上你可以修改这些反代软件的 QUIC 拥塞控制算法并编译,以实现有些人想要的暴力发包。对于 XHTTP 客户端:
alpn
仅有 "http/1.1" 则使用 HTTP/1.1(但 Xray 并不会允许它修改 uTLS 浏览器指纹伪装)alpn
仅有 "h3" 则使用 quic-go H3tlsSettings
都会失效)如果你要确认 Xray 客户端实际使用的 HTTP 版本、host,以及 XHTTP mode、上下行分离等信息,将日志调至 "info" 级别即可。
代理的 QUIC H3 过 CDN,至少 XHTTP 是首个大规模实现的,开了条新路,毕竟有的地区、有的运营商对 H3 审查不严,
不过也有的会 Q 死。即使后来我们开发了 stream-up 模式并发现了加上 gRPC header 伪装就能穿透 CF,也只作用于 H2,看来这个崭新的时代的含金量还在不断上升。XMUX
既然我们提到了 H2 和 H3,就不得不提它们的多路复用:均为 0-RTT,区别是 H3 没有 H2 的 TCP 队头阻塞问题,并且支持连接迁移,客户端换网也不会断。
那么经常研读 RFC 的朋友就会问了:如何具体控制它们的多路复用?我们设计了一个简洁而强大的接口,即 XMUX:maxConcurrency
:每条 TCP/QUIC 连接中最多同时存在多少代理请求,连接中的代理请求数量达到该值后 core 会建立新的连接,以容纳更多的代理请求。XMUX 全为 0 时该项默认值为 "16-32",每次随机。maxConnections
:最多同时存在多少条连接,连接数达到该值前每个新的代理请求都会开启一条新的连接,此后 core 会开始复用已有的连接。该值与maxConcurrency
冲突,只能二选一。默认值 0,即不限制,支持填写范围,每次随机。cMaxReuseTimes
:一条连接最多被复用几次,复用该次数后将不会被分配新的代理请求,将在内部最后一条代理请求关闭后断开。默认值 0,即不限制,支持填写范围,每次随机。hMaxRequestTimes
:@xqzr 发现 Nginx 默认最多允许每条 TCP/QUIC 连接累计承载 1000 个 HTTP 请求,XMUX 全为 0 时该项默认值为 "600-900" 取随机,否则该项默认 0 即不限制。该项基于 HTTP 请求计数,一般来说 stream-one 只产生一个 HTTP 请求,stream-up 是两个,packet-up 则是 N 个。该项计数不严谨,且 Golang 的 GET 请求有自动重试,故不建议顶格填写,那些 CDN 什么的要试出来。其中 packet-up 上行循环 POST 时若超过该值会自动切换到另一个 TCP/QUIC 连接,占它一个 reuseTimes 但不占 concurrency。 其实按 XMUX 的三项默认值,stream-* 不会超限,就 packet-up 会超,而它是 H3 的默认 mode,所以新增该项又主要是利好了 H3。hMaxReusableSecs
:@xqzr 发现 Nginx 默认最多允许每条 TCP/QUIC 连接被复用一个小时,XMUX 全为 0 时该项默认值为 "1800-3000" 取随机,否则该项默认 0 即不限制。TCP/QUIC 连接持续该时间后将不会被分配新的 HTTP 请求,将在内部最后一个 HTTP 请求关闭后断开。其中 packet-up 上行循环 POST 时若超过该值会自动切换到另一个 TCP/QUIC 连接,占它一个 reuseTimes 但不占 concurrency。hKeepAlivePeriod
:H2 / H3 连接空闲时客户端每隔多少秒发一次保活包,默认 0,即 Chrome H2 的 45 秒,或 quic-go H3 的 10 秒。它是 XMUX 里唯一不允许填范围(该项取随机才是特征)且允许填负数(比如填 -1 关掉空闲保活包)的项,建议留 0。XMUX 提供的这些参数可以组合出各种用法,比如多线程测速前需要设
"maxConcurrency" 1
,而“无限”复用可以设"maxConnections" 1
。即使你懒得研究也没事,当这些值全为 0 时就会取到上面写的三个默认值,相当于隔段时间就换个新的 H2/H3 主连接,相当丝滑,不会有 gRPC、HTTP 传输层始终复用同一条连接导致的“断流”体验。同样,这些参数都可以通过extra
下发给客户端。注:全不填也相当于全为零,会取到三个默认值,但若填了任一项,其它项就没有默认值了,全都要自己填,除前两项外其它项均可同时填。
此外,使用 XHTTP 时不要启用 mux.cool,并且新版 Xray 服务端已有检查,只接受纯 XUDP。
关于 XMUX 的默认值,一些摘录:
文章下方还有讨论一些 Nginx 参数。
STREAM-UP/ONE
终于轮到 XHTTP 的另一个重要模式了:“流式上行、流式下行”的 stream-up,顾名思义这种模式的上行也是流式的,从而不会牺牲上行效率。 它本来是为 REALITY 而开发的,直到我们发现加个 gRPC header 伪装 H2 就能穿透 CF(需要在面板中开启 gRPC 支持),并且 Nginx 等反代软件的支持也不错(Nginx 推荐 grpc_pass,简单省事),所以
mode
默认值 "auto" 的行为是:downloadSettings
时 stream-up),否则 packet-up它们的实现方式是(非开发者可以跳过):
POST /yourpath/sameUUID
即可,也有Referer: ...?x_padding=XXX...
POST /yourpath/
即可,响应即为下行,双向流式,请求头、响应头均有 header padding/yourpath
,实际请求的是/yourpath/
,若末尾没有/
会自动补上Content-Type: application/grpc
以伪装成 gRPC(可以设置noGRPCHeader
以关闭)noSSEHeader
那么经常使用 gRPC 的朋友就会问了:stream-up 比 gRPC 传输层有什么优势呢?
当然,XHTTP 相较于 WebSocket、HTTPUpgrade 的优势,除了“没有 ALPN 为 http/1.1 的显著特征”外,相信你都看到这里了,心里也早已有了答案,我就不一一列举了,
主要是太多了也不好列。上下行分离
压轴登场的当然是又一个崭新的时代:上下行分离。 我们大概知道,现在 GFW 针对 TLS in TLS 等流量特征的检测是基于单条连接,那么如果我们把上下行拆分到不同的审查系统,比如上行跑 IPv4 的 TCP,下行跑 IPv6 的 UDP,GFW 就会一时反应不过来。而由于 XHTTP 服务端仅基于 path 中随机生成的 UUID 关联上下行,packet-up 和 stream-up 天生就具有真正的上下行分离能力,且由于 XHTTP 可以穿透各种 CDN、可以搭配 REALITY 等,可选姿势也无限多。对于客户端,需要设置
downloadSettings
:可以看出,
downloadSettings
其实就是一套全新的streamSettings
,但是多了类似于 VLESS 出站中的address
和port
以指向另一个入口。显然其中network
必须为 "xhttp"(不可省略),security
可以为 "tls" 或 "reality"。sockopt
项也可被分享,但接收方可以在上行的sockopt
里将penetrate
设为 true 以覆盖下行,适合打mark
的情况。除该特例外,上下行分离时下行配置是完全独立的,不会继承上行的任何配置,而且比如,即使上下行均未填 XMUX 从而取默认值时,它们分别在 range 内 roll 出的确定值也是相互独立、无关的,这样随着时间的推移,上下行的复用完全不对称,切换主连接的时间点也不同,反分析效果更好。因为 GFW 若要对上下行分离动手,“主连接发起的时间点相同”肯定是最重要的切入点,所以以后 XHTTP 还会允许一开始就以不同的时间点发起上下行连接。其实如果你套了 CDN,甚至不需要修改服务端配置就可以玩转上下行分离,比如你可以优选出一个 IPv4 跑 TLS H2,再优选出一个 IPv6 跑 QUIC H3。而且 CDN 基本都支持“同域域前置”,比如上行
serverName
填 "a.example.com",下行serverName
填 "b.example.com",上下行host
均填 "c.example.com",实现外部 SNI 看起来也不同,当然如果你本来就有两个域名就更好了。如果你没有任何域名的话,也可以开两台 VPS、开两个 REALITY 玩上下行分离:无论是 CDN 加反代,还是 REALITY 加回落,只要最终以同一 path 抵达同一 VPS 上的同一 XHTTP 入站即可。总之由于 XHTTP 到处都能用,可随意搭配出来的组合是无限的,唯一的问题是脑洞够不够大。比如上下行分离问世后,很多人的用法其实是把上行分给去程优的线路、把下行分给回程优的线路,这样也挺实用的。
比如你可以再给上行设
"maxConnections": 1
,给下行设"maxConcurrency": 1
,实现上行的少量数据都走同一条底层连接,而下行的大量数据分散到不同的底层连接上,同时兼具反审查、低延迟、高速度,有点像 Switch,搭配 Vision Seed 食用效果更佳。上面贴出了一份涵盖了所有参数的配置示例,主要是为了让大家知道每一项应该写在哪,并说明一下前文中没怎么解释的参数:
extra
是host
、path
、mode
以外的所有参数的原始 JSON 分享方案,当extra
存在时,只有该四项会生效。且分享链接中只有这四项,GUI 一般也只有这四项,因为extra
中的参数都相对低频,且应当由服务发布者直接下发给客户端,不应该让客户端随意改。补充说明:“下发”的意思是“人去下发”,就是服务发布者写好
extra
后整个放进分享链接,客户端直接作为自己的extra
就可以用。host
的行为与 Xray 其它基于 HTTP 的传输层一致,客户端发送 host 的优先级为host
>serverName
>address
。服务端若设了host
,将会检查客户端发来的值是否一致,否则不会检查,建议没事别设。host
不可填在headers
内。Beyond REALITY
去年初我回归并写了
秒天秒地秒空气的REALITY,一举解决了多个痛点,然后就天天泡夜店没怎么管了,连文章都鸽到了现在还没完成,XUDP UoT Migration 更可惜,去年文章快写完了都没发,不知不觉 REALITY 已悄然成长为直连主力,经常能看到 XX 被封了下面的评论是推荐换 REALITY,口碑是有目共睹的,甚至因为过于稳定,这里都没以前热闹了。虽然 Xray 也为其它 transports 做出过大量优化、改进,但 XHTTP 是第一个 Xray 原生的传输层,第一个就整了波大的,当你看完这篇文章,也清楚 XHTTP 可以和 REALITY 一起用:Beyond REALITY 的意思并非是取代 REALITY,而是流行程度超越 REALITY。毫不夸张地说,正如 Xray 一贯的风格,XHTTP 的出现使得其它基于 HTTP 的传输层全部黯然失色,这就是 XHTTP 全场景通吃的时代。它将会比上一个成功的协议 REALITY 更加流行,因为 XHTTP 的特性就已经决定了它的覆盖面会更广。
最后,希望 XHTTP 的出现能够给大家带来一点小小的震撼,正如 Xray 历史上多次做到的那样:变革、推陈出新,始终是 Xray 的信仰。
若本文对你有所帮助,支持一个 REALITY NFT:
一篇介绍 REALITY 的文章将于接下来几天发布变成了介绍 XHTTP在大家的支持下,Project X NFT 已翻五六倍,对于 Project X NFT 首发时观望的朋友,这是一次弥补遗憾的好机会。
当然若你有余力,能支持个 Project X NFT 就更感谢了:
0xDc3Fe44F0f25D13CACb1C4896CD0D321df3146Ee
若还有哪里不清楚请在下方留言,我会更新文章,
建议不要过早出翻译版。Beta Was this translation helpful? Give feedback.
All reactions