vmess
介绍一下 vmess 协议,在配置 v2ray 的时候,会使用到它
底层协议
VMess 是一个基于 TCP 的协议,所有数据使用 TCP 传输。
背景介绍
vmess 协议是由 V2Ray 原创并使用于 V2Ray 的加密传输协议,是为了对抗墙的深度包检测而研发的
vmess 链接
一个 vmess 的链接可能长这样,以 vmess 协议开头,后面是一个字符串
vmess://eyJ2IjoiMiIsInBzIjoiZXhhbXBsZV9zZXJ2ZXIiLCJhZGQiOiIxMjMuNDU2Ljc4OS4xMCIsInBvcnQiOiI1Njc4OSIsImlkIjoiYWJjZGUxMi0zNDU2LTc4OTAtYWJjZC1lZjEyMzQ1Njc4OTAiLCJhaWQiOiIwIiwibmV0IjoidGNwIiwidHlwZSI6Im5vbmUiLCJob3N0IjoiZXhhbXBsZS5jb20iLCJwYXRoIjoiIiwidGxzIjoiIn0=它是一个 base64 加密的字符串,我们尝试解密:
const base64String = atob('eyJ2IjoiMiIsInBzIjoiZXhhbXBsZV9zZXJ2ZXIiLCJhZGQiOiIxMjMuNDU2Ljc4OS4xMCIsInBvcnQiOiI1Njc4OSIsImlkIjoiYWJjZGUxMi0zNDU2LTc4OTAtYWJjZC1lZjEyMzQ1Njc4OTAiLCJhaWQiOiIwIiwibmV0IjoidGNwIiwidHlwZSI6Im5vbmUiLCJob3N0IjoiZXhhbXBsZS5jb20iLCJwYXRoIjoiIiwidGxzIjoiIn0=')
const result = JSON.parse(base64String)
console.log(result)
/**
{
"v": "2",
"ps": "example_server",
"add": "123.456.789.10",
"port": "56789",
"id": "abcde12-3456-7890-abcd-ef1234567890",
"aid": "0",
"net": "tcp",
"type": "dtls",
"host": "example.com",
"path": "",
"tls": ""
}
*/发现其就是一个 JSON 对象,里面声明了服务器的 IP 地址、端口、用户 ID、以及相关的描述信息
入站/出站
vmess 协议不像传统的 C/S 架构,有明确的客户端和服务端之分。vmess 更像是一个节点,即可当做客户端,也可以当做服务端。每个节点都声明了入站和出站的配置,这意味我们可以将多个 VPN 节点组合起来,形成节点网络
假设我们配置一个最简单的 VPN 访问,只需要两个节点,一个是客户端,就是我们当前的设备,另一个是服务端,是可以访问外网的设备,可以是服务器或者是 VPS。这是两个节点的配置的一个示例:
{
"inbounds": [
{
"port": 1080, // 监听端口
"protocol": "socks", // 入口协议为 SOCKS 5
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"]
},
"settings": {
"auth": "noauth" //socks的认证设置,noauth 代表不认证,由于 socks 通常在客户端使用,所以这里不认证
}
}
],
"outbounds": [
{
"protocol": "vmess", // 出口协议
"settings": {
"vnext": [
{
"address": "serveraddr.com", // 服务器地址,请修改为你自己的服务器 IP 或域名
"port": 16823, // 服务器端口
"users": [
{
"id": "b831381d-6324-4d53-ad4f-8cda48b30811", // 用户 ID,必须与服务器端配置相同
"alterId": 0 // 此处的值也应当与服务器相同
}
]
}
]
}
}
]
}{
"inbounds": [
{
"port": 16823, // 服务器监听端口
"protocol": "vmess", // 主传入协议
"settings": {
"clients": [
{
"id": "b831381d-6324-4d53-ad4f-8cda48b30811", // 用户 ID,客户端与服务器必须相同
"alterId": 0
}
]
}
}
],
"outbounds": [
{
"protocol": "freedom", // 主传出协议
"settings": {}
}
]
}上面的关键信息是确保客户端和服务端的 id 是相同的,这是一个 uuid 的结构,可以使用随机生成器生成。相当于密码的作用,勿轻易泄露
inbounds 和 outbounds 用于声明入站和出站的配置,它们都是数组,这意味着可以配置多个入口和出口
原理解析
客户端:客户端配置中的 inbounds,port 为 1080,即 V2Ray 监听了一个端口 1080,协议是 socks
再看 outbounds,协议是 vmess,说明 V2Ray 接收到数据包之后要将数据包打包成 vmess 协议并且使用预设的 id 加密(这个例子 id 是 b831381d-6324-4d53-ad4f-8cda48b30811),然后发往服务器地址为 serveraddr.com 的 16823 端口。
服务端:服务器配置的 id 是 b831381d-6324-4d53-ad4f-8cda48b30811,所以 V2Ray 服务器接收到客户端发来的数据包时就会尝试用 b831381d-6324-4d53-ad4f-8cda48b30811 解密,如果解密成功再看一下时间对不对,对的话就把数据包发到 outbound 去
outbound.protocol 是 freedom(freedom 的中文意思是自由,在这里姑且将它理解成直连吧),数据包就直接发到 google.com 了