Files

183 lines
6.8 KiB
Markdown
Raw Permalink Normal View History

2026-05-24 11:42:38 +08:00
---
tags: [计算机网络, WireGuard, VPN, ChaCha20, Curve25519, OpenVPN, IPsec]
create time: 2026-05-18 05:35
---
# WireGuard VPN 原理与实践
## 概述
WireGuard 是一个极简的 VPN 协议,代码量不到 OpenVPN 的 1/10、IPsec 的 1/25。它凭借极低的延迟和超高的吞吐量,正在成为新一代标准 VPN 方案——甚至已合入 Linux 内核(≥ 5.6)。
## 为什么比 OpenVPN / IPsec 快?
```mermaid
flowchart LR
IPsec["IPsec\n• IKEv2 密钥交换 (多轮 RTT)\n• ESP/AH 扩展头链\n• 用户态+内核态来回跳转\n• ~10-20 种 cipher suite 协商"]
WG["WireGuard\n• Curve25519 密钥交换 (单次)\n• ChaCha20-Poly1305 AEAD\n• 纯内核态实现 (netlink API)\n• 仅 4 种密码学原语"]
style IPsec fill:#DDA0DD,color:#000
style WG fill:#98FB98,color:#000
```
### 性能对比实测数据
| 指标 | WireGuard | OpenVPN (UDP) | IPsec |
|------|-----------|--------------|-------|
| **吞吐量** | ~9.5 Gbps | ~1.5 Gbps | ~3.0 Gbps |
| **CPU 占用 (Gbps)** | 0.8% | 12.5% | 3.2% |
| **握手延迟** | < 1ms | 50-200ms | 100-300ms |
| **代码行数** | ~4,000 LoC | ~50,000 LoC | ~100,000 LoC |
| **配置复杂度** | 极简 (INI 格式) | 中等 | 复杂 |
| **NAT 遍历** | 原生支持 | 需要辅助 (UDP encapsulation) | 复杂 |
| **移动性** | 支持 (PersistentKeepalive + endpoint change) | 部分支持 | 有限支持 |
> [!tip] 代码行数少 = 更少的 bug = 更高的安全性
>
> 审计 ~4000 行 C 代码的成本远低于审计 ~50000 行。而且每少一行代码就少一个潜在的漏洞入口。
## WireGuard 的密码学基础
```
WireGuard 仅使用 4 种经过严格审查的密码学原语:
───────────────────────────────────────────────
1. Curve25519 — ECDH 密钥交换 (x25519)
2. ChaCha20 — 对称加密 (AES 替代)
3. Poly1305 — MAC / AEAD 认证
4. SHA-512 — 哈希函数
没有: RSA, ECC(除Curve25519外), CBC, HMAC, DRBG...
→ 选择极少 → 无协商 → 更快更简单
```
### 三重加密手风琴 (Triple Handshake)
```mermaid
sequenceDiagram
participant A as Peer A
participant B as Peer B
Note over A,B: 1. A → B: 主动握手 (A 发起)
A->>B: {Ephemeral Key A} 用 B's Static Key 加密
B->>A: {Ephemeral Key B} 用 A's Ephemeral Key + B's Static Key 加密
A->>B: {Empty} 用 A's Ephemeral Key + B's Ephemeral Key 加密
Note over A,B: ✅ 三方加密完成, 会话密钥建立
Note over A,B: 2. B → A: 响应式重握手 (B 轮换密钥)
B->>A: {Ephemeral Key B'} 用 A's Static Key 加密
A->>B: {Ephemeral Key A'} 用 B's Ephemeral Key + A's Static Key 加密
B->>A: {Empty} 用 B's Ephemeral Key + A's Ephemeral Key 加密
Note over A,B: ✅ 新会话密钥, 前向保密保证
```
> [!question] 什么是前向保密 (Forward Secrecy)?
> 即使长期密钥(Static Key)未来被泄露,也无法解密过去的通信——因为每次会话都使用了临时的 Ephemeral Key。三重手风琴保证了每一轮的临时密钥都在下一轮中被"销毁"。
## WireGuard 配置详解
### server.conf
```ini
[Interface]
Address = 10.0.0.1/24 # WireGuard 虚拟网卡 IP
ListenPort = 51820 # UDP 监听端口
PrivateKey = <server_private_key> # 私钥 (安全保存!)
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # NAT 转发
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
[Peer] # 客户端 1
PublicKey = <client1_public_key>
AllowedIPs = 10.0.0.2/32 # 只允许这个 IP 通过这个 peer
PersistentKeepalive = 25 # 每 25s 发一次 keepalive (穿透 NAT)
[Peer] # 客户端 2
PublicKey = <client2_public_key>
AllowedIPs = 10.0.0.3/32
PersistentKeepalive = 25
```
### client.conf
```ini
[Interface]
Address = 10.0.0.2/24 # 客户端自己的虚拟 IP
PrivateKey = <client_private_key> # 客户端私钥
# DNS 解析通过隧道走 VPN
DNS = 10.0.0.1
[Peer]
PublicKey = <server_public_key> # ⚠️ 注意方向: 客户端存服务端的公钥
Endpoint = vpn.example.com:51820 # 服务器地址
AllowedIPs = 0.0.0.0/0 # 所有流量走 VPN (全隧模式)
# AllowedIPs = 10.0.0.0/24 # 仅内网流量走 VPN (-split tunneling)
PersistentKeepalive = 25
```
### 一键生成密钥对
```bash
# 生成服务器密钥对
$ wg genkey | tee server-private.key | wg pubkey > server-public.key
# 生成客户端密钥对 (可重复 N 次)
$ wg genkey | tee client1-private.key | wg pubkey > client1-public.key
$ wg genkey | tee client2-private.key | wg pubkey > client2-public.key
# 生成 QR Code (方便手机扫码连接)
$ qrencode -t UTF8 <(cat <(echo "[Interface]"); echo "PrivateKey=$(cat client1-private.key)"; echo "[Peer]"; echo "PublicKey=$(cat server-public.key)"; echo "AllowedIPs=0.0.0.0/0"; echo "Endpoint=vpn.example.com:51820"; echo "PersistentKeepalive=25")
```
### 日常运维命令
```bash
# 启动 WireGuard
$ sudo wg-quick up wg0
$ sudo systemctl enable --now wg-quick@wg0 # 开机自启
# 查看状态
$ wg show
interface: wg0
public key: abc123def456...
private key: (hidden)
listening port: 51820
peer: xyz789ghi012...
endpoint: 203.0.113.5:45678
allowed ips: 10.0.0.2/32
latest handshake: 3 seconds ago ← 3 秒前还在握手! 连接活跃
transfer: 1.23 GiB received, 890 MiB sent
# 动态添加/移除 peer (不需要重启!)
$ wg set wg0 peer <new_pubkey> allowed-ips 10.0.0.4/32
$ wg remove wg0 peer <old_pubkey>
# 导入导出配置
$ wg syncconf wg0 <(wg-quick strip wg0)
```
## WireGuard 的限制与注意事项
```
⚠️ WireGuard 不适合的场景:
─────────────────────────────────
• 需要传统用户认证 (PAP/CHAP/LDAP) → WireGuard 只认密钥
• 细粒度 per-user 带宽控制 → 需配合 tc (traffic control)
• 大规模动态节点 (千级以上) → 管理 1000 个 peer 的 AllowedIPs 很痛苦
• 与现有 IPsec 设备互通 → WireGuard 不能做 IPsec gateway
✅ WireGuard 非常适合:
─────────────────────────────────
• 个人/小团队私有 VPN
• 云服务器到 IDC 的专线
• IoT 设备远程管理
• Kubernetes 集群跨 AZ 通信
```
## 关联笔记
- [[hhs/NETWORK/eBPF与ServiceMesh]] — eBPF 可用于监控 WireGuard 接口的流量
- [[hhs/NETWORK/SDNSRv6与网络编程最佳实践]] — SDN + SRv6 是更宏大的网络可编程愿景
- [[hhs/NETWORK/IPv6地址与扩展头部]] — IPv6 SLAAC 自动配置与 WireGuard 的静态分配对比