本页目录

正向代理

客户端侧的代理——HTTP CONNECT 为 HTTPS 建立 TCP 隧道直达目标,SOCKS5 支持任意 TCP 和 UDP 流量转发。PAC 把"哪些流量走代理"变成可编程的决策逻辑,而非全有或全无的开关。

概述

正向代理是客户端侧的代理——client 配置代理服务器地址,所有出站流量经过代理。HTTP CONNECT 方法允许代理建立端到端 TCP 隧道(用于 HTTPS),SOCKS5 更底层——支持任意 TCP 流量和 UDP 转发。PAC 提供动态的 per-URL 代理决策。正向代理与反向代理对称:前者是 client 侧,后者是 server 侧。

HTTP CONNECT: TCP 隧道

当浏览器配置了 HTTP 代理,HTTPS 请求不是直接发给目标服务器——它用 CONNECT 方法建立一个端到端 TCP 隧道:

Client → Proxy:
  CONNECT example.com:443 HTTP/1.1
  Host: example.com:443
  Proxy-Authorization: Basic <base64(user:pass)>

Proxy → example.com:443: TCP 3-way handshake
Proxy → Client:
  HTTP/1.1 200 Connection Established   ← 隧道已建立

后续: 客户端和 server 之间的 TLS 握手直接在隧道上进行:
  Client ↔ Proxy ↔ Server (TCP 层面转发, 不解析内容)
  → 代理看不到 HTTP body (它被 TLS 加密了)
  → 但代理看到 CONNECT 目标 (SNI 在 TLS ClientHello 中, 也是明文)

CONNECT 与普通 GET 的区别:

GET http://example.com/index.htmlCONNECT example.com:443
代理角色HTTP 代理: 解析 HTTP, 重构请求TCP 隧道: 字节流转发
TLS无需 (目标用 HTTP)Client ↔ Server 端到端
代理看到内容否 (加密)

SOCKS5

SOCKS5 是独立于 HTTP 的代理协议, 工作在 TCP 层。规则: 3 次握手 (method negotiation, request, reply) → 纯 TCP 转发。

1. Method Negotiation (认证):
   Client → Server:
     VER=5, NMETHODS=1, METHODS=0x00  (0x00=no auth, 0x02=user/pass)
   Server → Client:
     VER=5, METHOD=0x00

2. Request:
   Client → Server:
     VER=5, CMD, RSV=0x00, ATYP, DST.ADDR, DST.PORT
     
     CMD: 0x01=CONNECT(TCP), 0x02=BIND(反连, FTP active mode), 0x03=UDP ASSOCIATE
     ATYP: 0x01=IPv4(4 bytes), 0x03=Domain name(1 byte len + name), 0x04=IPv6(16 bytes)
     DST.PORT: 2 bytes (network byte order)

   Server → Client:
     VER=5, REP, RSV=0x00, ATYP, BND.ADDR, BND.PORT

     REP: 0x00=success, 0x01=general SOCKS server failure,
          0x02=connection not allowed, 0x03=Network unreachable,
          0x04=Host unreachable, 0x05=Connection refused,
          0x06=TTL expired, 0x07=Command not supported,
          0x08=Address type not supported

3. Data Relay: 双向 TCP 转发 (server 在 Client↔Target 之间透明转发字节)

DNS 解析

SOCKS5 client 发送域名 (ATYP=0x03) 而不是 IP → SOCKS5 server 负责 DNS 解析。

意义: 如果 client 本机的 DNS 被污染, SOCKS5 server 可以走自己的 DNS (如 8.8.8.8), 绕过本地劫持。

UDP ASSOCIATE

SOCKS5 也支持 UDP 转发:

Client → Server: CMD=UDP ASSOCIATE, DST.ADDR=0.0.0.0, DST.PORT=0
Server → Client: REP=success, BND.ADDR=<server UDP relay IP>, BND.PORT=<port>
后续: Client 发 UDP datagram 到 BND.ADDR:BND.PORT, 前面加一个 SOCKS5 UDP header:
  [RSV 2B][FRAG 1B][ATYP 1B][DST.ADDR][DST.PORT][DATA]

PAC

PAC 是 JavaScript 脚本,浏览器在每次请求前执行它,根据 URL/host 动态决定走不走代理:

function FindProxyForURL(url, host) {
    // 局域网 → 直连
    if (isInNet(host, "192.168.0.0", "255.255.0.0")) return "DIRECT";
    if (shExpMatch(host, "*.local"))              return "DIRECT";
    // 国内 → 直连
    if (shExpMatch(host, "*.cn"))                 return "DIRECT";
    // 其他 → 代理
    return "PROXY 127.0.0.1:7890; SOCKS5 127.0.0.1:1080; DIRECT";
}

PAC 与浏览器代理设置的区别: 传统代理设置是静态的 (on/off)。PAC 提供了 per-request 的动态规则。return "DIRECT" 表示不走代理。

参考

  • RFC: 7231 (CONNECT), 1928 (SOCKS5), 1929 (SOCKS5 user/pass auth)
  • mihomo: wiki.metacubex.one (mixed port = HTTP + SOCKS5 自动检测)
  • 工具⁠: curl --proxy socks5h://127.0.0.1:1080 https://example.com (socks5h = 代理做 DNS 解析)

Keywords: HTTP CONNECT, SOCKS5, PAC, forward proxy, TCP tunnel, UDP ASSOCIATE