Skip to content
0

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 了

参考资料

v2fly

Released under the MIT License.