冲浪小本本儿(八) ------ 尝鲜xhttp 上下行分离最简配置

本文参考
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)记录:
8-0-5-1
在客户端的日志中也可以看到以下记录:
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

一些思考

  1. 最早关于上下行分离链路的设想可以追溯到这篇文章: 希望能增加 上下行分离链路 · 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 地址

  1. 头部填充让我想起 “例如,谷歌浏览器105版发送的TLS Client Hello包,由于用零填充,每字节平均只有1.56个1比特,属于豁免范围。”相关信息可以参考 中国的防火长城是如何检测和封锁完全加密流量的 不知道r佬是不是从这里得到灵感
    从这篇文章来看,GFW 的豁免规则还有很多,不知道是否可以根据这些规则尝试改造数据包

[1] 冲浪小本本儿(一) :heavy_check_mark:
[2] 冲浪小本本儿(一)(1-1) byedpi/zapret/spoofdpi :heavy_check_mark:
[3]冲浪小本本儿(二)---- http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[1]— 简单说两句http;查看http报文;HTTP的TCP握手;OSI模型下的HTTP :heavy_check_mark:
[4] 冲浪小本本儿(二)(2-1)---- http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[2]— 简单说两句https;非常重要的自签证书;后量子加密 :heavy_check_mark:
[5] 冲浪小本本儿 (二)(2-2)----http-https-ECH 最广泛、最真实、最管用的互联网隐私保护[3]— ECH详谈;什么是DNS HTTPS类型记录;查看dns type HTTPS (type 65)记录获得ECH参数(echconfig);客户端如何获得EchConfig;浏览器访问网站完整流程;通过wrieshark 抓包 ECH;降级HTTP3到HTTP2;在客户端禁用ECH;关于ECH的特征:heavy_check_mark:
[6]冲浪小本本儿 (二)(2-3)----伊友闹得欢,rprx拉清单,小圈子大新闻始末 :heavy_check_mark:
[7]冲浪小本本儿 (三) — 什么是desync类工具,还有哪些直连类型工具;什么是正代反代,如何完成反代;steam++这类工具是怎么完成不连接第三方服务器直连的;简易反代制作;当你直连一个网站时外部能看到什么
[8]冲浪小本本儿 (三)(3-1) 什么是tun模式,为什么clash的tun模式叫tun模式,而不叫tunnel
[9] 冲浪小本本儿 (四) — 当你通过proxy翻墙时,会在日志里、服务器上留下什么,通过代理连接有哪些风险
[10] 冲浪小本本儿 (五) — 被墙的网站有哪些分级,一些简单的dns污染名单,sni阻断名单,直连有哪些风险
[11] 冲浪小本本儿 (六) — 如何对网站方隐藏自身,什么是浏览器指纹,怎么改变;分析怎么逃过宏迪追杀
[12] 冲浪小本本儿 (七) — 如何处理dns污染;低延迟但被污染的dns、高延迟但正确的dns怎么选?域名分流;doh本身被封了怎么办 :heavy_check_mark:
[13] 冲浪小本本儿 (七)(7-1)— 测试doh/dot/doq 是否被墙方法 ;adguard home自签证书让局域网内浏览器用上doh
[14]冲浪小本本儿(七) (7-2) — 旧文新更,从“DNS 在代理环境中的应用”说起;Firefox 使用自带的代理设置时, "使用 SOCKS v5 时代理 DNS 查询"开还是不开?令人尴尬的代理解析选择
[15]冲浪小本本儿(七) (7-3) — 不知道什么时候会开始写、能用得上的ODOH
[16]冲浪小本本儿(八) ---- 尝鲜xhttp 上下行分离最简配置 :heavy_check_mark:

2 个赞