本页目录
正向代理
客户端侧的代理——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.html | CONNECT 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 动态决定走不走代理:
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