# TCP + TLS + Web

新手建议使用 TLS 分流器 (opens new window) 方案

# 背景

  • 目前 Vmess + WebSocket + TLS (以下简称 wss)方式,因其特征如同 HTTPS 流量,可以隐藏 V2Ray 路径,主动侦测会得到正常 HTTP 网站响应,具有良好的伪装能力,目前被广泛用于反审查。

  • 但是如此强大的伪装能力,需要付出严重的性能代价:TLS 1.3 握手需要消耗 1-rtt,WS 握手也需要消耗 1-rtt,增大了握手延迟。V2Ray 增加了 mux 以减少握手的发生,然而实际使用中 mux 体验并不好,很多用户选择关闭。

  • 最近兴起了一个新的反审查工具——Trojan (opens new window),这个工具将一个类似 Socks 的协议直接通过 TLS 传输,并将认证失败的流量交由 Web 服务器处理。降低 WS 延迟的同时,提供与 wss 方式一样的伪装能力。但是该工具较为年轻,没有路由功能,各平台图形化客户端也不完善。

  • 因此,本人尝试用 V2Ray 实现类似功能,即 Vmess + TCP + TLS 并网站伪装,省下 WS 的握手延迟。

# 原理

HaProxy 监听 443 端口,处理 TLS 之后,将 HTTP 流量交由 Web 服务器处理,非 HTTP 流量交由 V2Ray 按 Vmess 处理。

# 实现

本次方案使用 HaProxy,Caddy/Nginx(Web 服务器的使用不是本教程的重点,可以用 httpd 等替代),V2Ray,服务器系统为 Debian 10。

  1. 安装 HaProxy apt install haproxy
  • 为了较好的支持 TLS1.3,HaProxy 版本应大于 1.8.15,OpenSSl 版本应大于 1.1.1,如果您使用的发行版仓库自带的版本较低,您可能需要自行编译安装。
  1. 安装 Web 服务器,Caddy 参考这个教程 (opens new window),Nginx 使用命令 apt install nginx安装。

  2. 安装 V2Ray,可以使用官方脚本官方脚本 (opens new window)

  3. 修改 V2Ray 配置文件,以 Vmess + TCP 方式监听 40001 端口。

{
    "inbounds": [
        {
            "protocol": "vmess",
            "listen": "127.0.0.1",
            "port": 40001,
            "settings": {
                "clients": [
                    {
                        "id": "f2435e5c-9ad9-4367-836a-8341117d0a5f"
                    }
                ]
            },
            "streamSettings": {
                "network": "tcp"
            }
        }
    ],
    "outbounds": [
        {
            "protocol": "freedom"
        }
    ]
}
  1. 修改 Web 服务器配置文件,部署 HTTP 服务于 8080 端口。

Caddy 直接替换

http://example.com:8080 {
    root /var/www/html
}

Nginx 在 http{} 里面添加

server {
  listen 8080;
  server_name example.com;
  root /var/www/html;
}
  • 注:/var/www/html 是静态网站目录

  • 实际服务请根据需要部署,也可以用 httpd 之类的替代

  • 似乎很多 Trojan 教程直接监听 80 端口,其实很多 HTTPS 网站 80 端口通常是重定向到 HTTPS

  1. 修改 HaProxy 配置文件。
global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # 仅使用支持 FS 和 AEAD 的加密套件
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    # 禁用 TLS 1.2 之前的 TLS
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11

    tune.ssl.default-dh-param 2048

defaults
    log global
    # 我们需要使用 tcp 模式
    mode tcp
    option dontlognull
    timeout connect 5s
    # 空闲连接等待时间,这里使用与 V2Ray 默认 connIdle 一致的 300s
    timeout client  300s
    timeout server  300s

frontend tls-in
    # 监听 443 tls,tfo 根据自身情况决定是否开启,证书放置于 /etc/ssl/private/example.com.pem
    bind *:443 tfo ssl crt /etc/ssl/private/example.com.pem
    tcp-request inspect-delay 5s
    tcp-request content accept if HTTP
    # 将 HTTP 流量发给 web 后端
    use_backend web if HTTP
    # 将其他流量发给 vmess 后端
    default_backend vmess

backend web
    server server1 127.0.0.1:8080
  
backend vmess
    server server1 127.0.0.1:40001
  • HaProxy 的证书和密钥放于同一个文件,与 Caddy 和 Nginx 不同,可以使用命令 cat example.com.crt example.com.key > example.com.pem 合成证书
  1. 重启服务
systemctl restart haproxy
systemctl restart caddy
systemctl restart v2ray
  1. 客户端连接 example.com:443 vmess tls 即可
{
    "inbounds": [
        {
            "port": 1080,
            "listen": "127.0.0.1",
            "protocol": "socks"
        }
    ],
    "outbounds": [
        {
            "protocol": "vmess",
            "settings": {
                "vnext": [
                    {
                        "address": "example.com",
                        "port": 443,
                        "users": [
                            {
                                "id": "f2435e5c-9ad9-4367-836a-8341117d0a5f",
                                "security": "none"
                            }
                        ]
                    }
                ]
            },
            "streamSettings": {
                "network": "tcp",
                "security": "tls"
            }
        }
    ]
}

# 效果

延迟对比

  • 测试工具为 vmessping (opens new window),可见 Vmess + TCP + TLS(左)延迟低于 Vmess + WSS(右)

  • 打开网站域名可以看到正常的网站。

# 讨论

  • 该方法的隐蔽性是否比 wss 低?
    • 中间人看来,该方法在建立 TLS 连接后,比 wss 少一次握手,即 TLS 建立后直接发送请求并获得响应,该行为是符合正常的 HTTPS 请求的。
    • 主动探测时,如 TLS 建立后发送 HTTP 请求,则被发给 Web 服务器按正常 HTTP 请求处理。如发送非 HTTP 请求,会被发给 V2Ray 处理,如 Vmess 认证失败,连接将被关闭,向 HTTPS 服务器发送非 HTTPS 请求,连接被关闭是正常的行为。
    • 如果您还认为存在被检测的的可能,请提出检测方法。