本文参考
xhttp 五合一配置 ( reality 直连与过 CDN 共存, 附小白可抄的配置) · XTLS/Xray-core · Discussion #4118 · GitHub
XHTTP
XHTTP: Beyond REALITY · XTLS/Xray-core · Discussion #4113 · GitHub
通过一步步对配置的修改、进阶来理解 XHTTP,了解rprx改造 HTTP 协议的野望
一、 vless+xhttp 无加密直连
client xray --------> server xray
服务端
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": null,
"port": 12345,
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "f2de4a5a-f886-423a-8251-e9bf119d195b"
}
]
},
"streamSettings": {
"network": "xhttp",
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
客户端
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": "127.0.0.1",
"port": 1080,
"protocol": "socks"
},
{
"listen": "127.0.0.1",
"port": 1081,
"protocol": "http"
}
],
"outbounds": [
{
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "192.168.59.130",
"port": 12345,
"users": [
{
"id": "f2de4a5a-f886-423a-8251-e9bf119d195b",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "xhttp",
"security": "",
"xhttpSettings": {
"host":"",
"path": "/7f5e1395",
"mode":"auto"
}
}
},
{
"protocol": "freedom",
"tag": "direct"
}
]
}
抓包分析下
先看”分包上行“,可以看到 xhttp 是模仿http协议的标准构造 ,POST方法, 路径为 /yourpath/sameUUID/seq ,参数 x_padding=000… 头部随机0填充用来消除特征
跳过HTTP/1.1 等标头
主体部分即vless协议设计参数, 参考 Project X
00 协议版本
f2 de 4a 5a f8 86 42 3a 82 51 e9 bf 11 9d 19 5b uuid
00 附加信息长度 M
01 指令
01 bb 访问网站的端口 443
01 访问网站的地址类型
XX XX XX XX 访问网站的ip地址
16 03 03 XXX … 访问网站的client hello
回包部分,自创了 X-Padding字段,同样用于填充。最初我对 HTTP 协议没有这个标头感到惊讶,查阅后发现这是 2012 年弃用的 X- 前缀自定义标头方案,详细信息见RFC 6648 - Deprecating the "X-" Prefix and Similar Constructs in Application Protocols
再看"流式下行"
使用 GET 方法,路径为 /yourpath/sameUUID,x_padding=000…。下行包没有像上行包一样使用配置里的 UUID 验证,而是依靠 sameUUID来验证
回包部分, transfer-Encoding: chunked 标头是流式下行的关键所在。分块传输编码(chunked transfer encoding)是一种HTTP传输编码方式,它可以在传输数据时将数据分成一个一个的小块,然后逐个发送,以达到流式传输的效果。Article - Xu Senlin's Personal Blog
后续部分包括访问网站的 Server Hello、证书和 Application Data。
这是 Packet-Up 模式的分析,关于 Stream-Up 和 Stream-One 的内容不做展开。
传统模式
访问网站
↓
client server
---------------------------------> ----> 访问网站
<------------------------------- <---- 访问网站
xhttp
访问网站
↓
client server
(up) ------------xhttp------------- > ---->访问网站 request
<------------------------------
(down) ----------xhttp ------------>
<------------------------------- <---- 访问网站 response
可以看出,与传统代理模式不同,Packet-Up 和 Stream-Up 在访问网站的代理流程中实现了实质性的分离。具体而言,访问网站的请求通过一条 TCP/UDP 路径发送,而访问网站返回的响应则通过另一条 TCP/UDP 路径传输,这为更灵活的上下行分离提供了基础。
vless 本身不加密,对访问网站的client hello、sever hello整个流程暴露出来了,公网上跑vless 最好套上tls或者reality,都借助第三方服务器了,还让访问的网站暴露出来,那还不如直接用 desync 类工具直连了,反正现在量子计算还没能破解RSA
二、 vless+xhttp+tls
自签证书请参考冲浪小本本儿(二)(2-1)
client xray —tls-----> server xray
服务端
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": null,
"port": 12345,
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "f2de4a5a-f886-423a-8251-e9bf119d195b"
}
]
},
"streamSettings": {
"network": "xhttp",
"security": "tls",
"tlsSettings": {
"alpn": "h2",
"certificates": [
{
"certificateFile": "serverup.crt",
"keyFile": "serverup.key"
}
]
},
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
客户端
在抓包分析中发现,与 VLESS + XHTTP 的配置不同,此时并未出现上下行分离。经过进一步检查 debug 日志,发现只有一条记录:transport/internet/splithttp: XHTTP is dialing to tcp:192.168.59.130:12345, mode stream-up, HTTP version 2, host upupupup.com。
在启用 TLS 或 Reality 的情况下,如果不进行上下行分离的配置,则不会产生上下行分离。在这种情况下,auto 默认使用 Stream-One 模式。
三、上行 vless+xhttp+tls |下行 vless+xhttp+tls
client xray ---up tls -----> server
---down tls---->
服务端
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": null,
"port": 12345,
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "f2de4a5a-f886-423a-8251-e9bf119d195b"
}
]
},
"streamSettings": {
"network": "xhttp",
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
},
{
"listen": null,
"port": 443,
"protocol": "vless",
"settings": {
"decryption": "none",
"fallbacks":[
{
"dest":"127.0.0.1:12345"
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"alpn": "h2",
"certificates": [
{
"certificateFile": "serverup.crt",
"keyFile": "serverup.key"
}
]
},
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
},
{
"listen": null,
"port": 8443,
"protocol": "vless",
"settings": {
"decryption": "none",
"fallbacks":[
{
"dest":"127.0.0.1:12345"
}
]
},
"streamSettings": {
"network": "tcp",
"security": "tls",
"tlsSettings": {
"alpn": "h2",
"certificates": [
{
"certificateFile": "serverdown.crt",
"keyFile": "serverdown.key"
}
]
},
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
客户端
client ----tls upupupup.com ----------> ipv6 443 --->12345
----tls downdowndown.com ---> ipv4 8443 ------↑
在服务端的 12345 端口上,启用了无加密的 XHTTP,同时在 443 和 8443 端口上分别接受加密的上行和下行流,解密后回落到 XHTTP。
抓包分析显示了两条 SNI(Server Name Indication)记录:
在客户端的日志中也可以看到以下记录:
transport/internet/splithttp: XHTTP is dialing to tcp:[fe80::b4fd:4ea9:42d9:9378]:443, mode stream-up, HTTP version 2, host upupupup.com
transport/internet/splithttp: XHTTP is downloading from tcp:192.168.59.130:8443, mode stream-down, HTTP version 2, host downdowndown.com
在测试过程中发现,由于无法在服务端的 network: “tcp” 设置中使用 UDP/QUIC,因此无法实现上行 H2 和下行 H3 的配置。
四、上行 vless+xhttp+reality |下行 vless+xhttp+nginx前置
client xray ---up reality ---------------> server
---down tls ---->nginx --------↑
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": null,
"port": 12345,
"protocol": "vless",
"settings": {
"decryption": "none",
"clients": [
{
"id": "f2de4a5a-f886-423a-8251-e9bf119d195b"
}
]
},
"streamSettings": {
"network": "xhttp",
"xhttpSettings": {
"host":"",
"mode":"auto",
"path": "/7f5e1395"
}
}
},
{
"listen": null,
"port": 443,
"protocol": "vless",
"settings": {
"decryption": "none",
"fallbacks":[
{
"dest":"127.0.0.1:12345"
}
]
},
"streamSettings": {
"host":"",
"mode":"auto",
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"target": "www.microsoft.com:443",
"xver": 0,
"serverNames": [
"www.microsoft.com"
],
"privateKey": "aO6XsClaCdvfqVgeNhiLMn6I3fCJv2akkDuyHLQllGk",
"shortIds": ["6ba85179e30d4fc2"]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
]
}
前置nginx
server {
http2 on;
listen 8443 ssl;
server_name downdowndown.com;
ssl_certificate serverdown.crt;
ssl_certificate_key serverdown.key;
location /7f5e1395 {
grpc_pass grpc://127.0.0.1:12345;
}
}
客户端
小结
以上都是最简配置,可配置项太多了, xmux配置多路复用、xPaddingBytes头部填充数量设置等等,sockopt 还能设置tcpFastOpen tcp快速打开,nginx也有大量配置,xhttp更像是在一整个模仿http协议将vless流量彻底改头换面成https流量,莫非翻墙协议的尽头就是模仿HTTPS
一些思考
- 最早关于上下行分离链路的设想可以追溯到这篇文章: 希望能增加 上下行分离链路 · Issue #2696 · v2ray/v2ray-core · GitHub
原拓扑图
client<--> 节点1 ------up -------> 节点2 <----> 目标网站
↓
<------down---- 节点3
根据目前 XHTTP 的实现,这一设想并不难以实现:
client ----- up ----->port A server xray ---回落---> port B server xray <---> 目标网站
------down---> nginx -----------------------------↑
发现有一些偏离设想本意,应当是由节点3向节点1(或者说client)主动发起SYN,但目前的上行和下行全都是由client主动发起
另一个问题是节点3无法直接与客户端握手,这可能是由于缺乏公网 IPv4 地址所致。然而,随着 IPv6 的普及,这一问题有望得到缓解。客户端在向节点2发起请求时,可以携带回程的 IPv6 地址
- 头部填充让我想起 “例如,谷歌浏览器105版发送的TLS Client Hello包,由于用零填充,每字节平均只有1.56个1比特,属于豁免范围。”相关信息可以参考 中国的防火长城是如何检测和封锁完全加密流量的 不知道r佬是不是从这里得到灵感
从这篇文章来看,GFW 的豁免规则还有很多,不知道是否可以根据这些规则尝试改造数据包
[1] 冲浪小本本儿(一)
[2] 冲浪小本本儿(一)(1-1) byedpi/zapret/spoofdpi
[3]冲浪小本本儿(二)---- http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[1]— 简单说两句http;查看http报文;HTTP的TCP握手;OSI模型下的HTTP
[4] 冲浪小本本儿(二)(2-1)---- http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[2]— 简单说两句https;非常重要的自签证书;后量子加密
[5] 冲浪小本本儿 (二)(2-2)----http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[3]— ECH详谈;什么是DNS HTTPS类型记录;查看dns type HTTPS (type 65)记录获得ECH参数(echconfig);客户端如何获得EchConfig;浏览器访问网站完整流程;通过wrieshark 抓包 ECH;降级HTTP3到HTTP2;在客户端禁用ECH;关于ECH的特征
[6]冲浪小本本儿 (二)(2-3)----伊友闹得欢,rprx拉清单,小圈子大新闻始末
[7]冲浪小本本儿 (三) — 什么是desync类工具,还有哪些直连类型工具;什么是正代反代,如何完成反代;steam++这类工具是怎么完成不连接第三方服务器直连的;简易反代制作;当你直连一个网站时外部能看到什么
[8]冲浪小本本儿 (三)(3-1) 什么是tun模式,为什么clash的tun模式叫tun模式,而不叫tunnel
[9] 冲浪小本本儿 (四) — 当你通过proxy翻墙时,会在日志里、服务器上留下什么,通过代理连接有哪些风险
[10] 冲浪小本本儿 (五) — 被墙的网站有哪些分级,一些简单的dns污染名单,sni阻断名单,直连有哪些风险
[11] 冲浪小本本儿 (六) — 如何对网站方隐藏自身,什么是浏览器指纹,怎么改变;分析怎么逃过宏迪追杀
[12] 冲浪小本本儿 (七) — 如何处理dns污染;低延迟但被污染的dns、高延迟但正确的dns怎么选?域名分流;doh本身被封了怎么办
[13] 冲浪小本本儿 (七)(7-1)— 测试doh/dot/doq 是否被墙方法 ;adguard home自签证书让局域网内浏览器用上doh
[14]冲浪小本本儿(七) (7-2) — 旧文新更,从“DNS 在代理环境中的应用”说起;Firefox 使用自带的代理设置时, "使用 SOCKS v5 时代理 DNS 查询"开还是不开?令人尴尬的代理解析选择
[15]冲浪小本本儿(七) (7-3) — 不知道什么时候会开始写、能用得上的ODOH
[16]冲浪小本本儿(八) ---- 尝鲜xhttp 上下行分离最简配置