Skip to content
/NetWork/vmess
10/30/2024
3.8m
AI 摘要

本文介绍 vmess 协议,它是 V2Ray 使用的加密传输协议,用于对抗深度包检测。vmess 链接是 base64 编码的 JSON 对象,包含服务器信息。配置时需确保客户端和服务端的 id 一致,inboundsoutbounds 分别定义入站和出站规则,支持构建节点网络。

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 端口。

socks
VMess
Freedom
浏览器
V2Ray 客户端1 inbound -> V2Ray 客户端1 outbound
V2Ray 服务器2 inbound -> V2Ray 服务器2 outbound
目标网站

服务端:服务器配置的 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.