为什么WireGuard 能进内核?
这是一个架构层面的必然结果,不是“实现水平”或“历史包袱”的问题。
一句话先给结论:
WireGuard 能进内核,是因为它在语义上就是“内核该干的事”;
OpenVPN 不能进内核,是因为它在语义上必然属于用户态。
下面我们从 内核准入条件 → 协议语义 → 工程后果 三层把它拆干净。
一、内核到底“允许什么样的东西进去”?
内核不是“性能更快的地方”,而是:
只允许那些:
- ✅ 行为可预测
- ✅ 状态有限且可验证
- ✅ 不依赖复杂策略
- ✅ 不需要频繁用户交互
- ✅ 安全失败方式清晰
的机制型组件
内核讨厌三样东西:
❌ 大状态机
❌ 动态协商
❌ 策略决策
这是判断一切能否进内核的第一道门槛。
二、WireGuard:它在语义上就是“内核模块”
我们直接看 WireGuard 在内核里“像什么”。
1️⃣ WireGuard ≈ 加密版 IP 层适配器
在内核视角中:
netif_rx() → wg_receive() → decrypt → inject into stack
它做的事非常像:
- GRE
- IPIP
- VXLAN(但更简单)
✅ 输入包 → 验证 → 解密 → 放回网络栈
✅ 输出包 → 查 peer → 加密 → 发 UDP
没有控制面 / 数据面分裂
2️⃣ WireGuard 的状态模型满足内核约束
| 状态 | 特点 |
|---|---|
| Peer | 长期、数量有限 |
| Endpoint | 事实型、可覆盖 |
| Keypair | 短期、自动轮换 |
| Counter | 单调、无回滚 |
✅ 没有“阶段”
✅ 没有“等待对方回应”
✅ 没有“协商失败重试”
这意味着什么?
内核线程永远不会卡在“等一个决定”上
3️⃣ WireGuard 的失败模式是“静默丢包”
这是内核最喜欢的失败方式:
- 解密失败 → drop
- counter 异常 → drop
- peer 不存在 → drop
✅ 没有弹窗
✅ 没有 UI
✅ 没有错误码泛滥
这和内核网络栈的哲学是完全一致的。
三、OpenVPN:它在语义上“必须是用户态”
注意:不是“实现选择”,而是语义决定了它不能下沉。
1️⃣ OpenVPN 的核心是一个“连接型协议”
OpenVPN 的真实结构是:
TCP/TLS 控制通道
↓
协商 cipher / 参数
↓
建立 data channel
↓
维持 session / keepalive
这意味着:
❌ 有明确的“连接建立”
❌ 有“连接失败原因”
❌ 有“重试策略”
这三点直接把它踢出内核。
2️⃣ TLS = 用户态专属物种
OpenVPN 依赖:
- TLS
- X.509
- 证书验证
- CRL / OCSP
- cipher 协商
这些东西意味着:
- 动态内存
- 大整数运算
- ASN.1 解析
- 可配置策略
内核永远不会接受一个“可配置密码学协商引擎”。
3️⃣ OpenVPN 必须“解释错误”
举几个 OpenVPN 的典型问题:
- 证书过期
- CA 不信任
- cipher 不匹配
- TLS 握手失败
这些错误:
❌ 需要人类理解
❌ 需要日志
❌ 需要策略判断
而内核只会做一件事:
要么转发,要么丢弃
四、控制面 vs 数据面:决定命运的分界线
这是最核心的一刀。
WireGuard
- 没有控制面
- handshake 是数据包的一种
- 所有包都可独立处理
✅ 纯数据面协议
OpenVPN
- 控制面 ≠ 数据面
- 连接管理 ≠ 数据转发
- 状态依赖顺序
❌ 控制面主导协议
五、工程后果:为什么结果“只能这样”
1️⃣ WireGuard 能做到:
- 内核实现 < 5k 行
- 可形式化审计
- 死锁路径极少
- 无需用户态守护进程
2️⃣ OpenVPN 如果进内核会发生什么?
你可以想象一下:
- TLS 栈进内核
- 证书解析进内核
- 配置解析进内核
- 重试逻辑进内核
👉 内核直接变成用户空间
这在安全上是不可接受的。
六、用一句“工程判断”总结
能进内核的,不是“跑得快”的代码,而是“不需要思考”的代码。
- WireGuard:
👉 收到包 → 验证 → 转发 - OpenVPN:
👉 收到包 → 判断 → 协商 → 决策 → 解释结果
内核只做前者。
七、终极对照总结(可以直接引用)
WireGuard 能进内核,是因为它本身就是一个“无控制面的加密转发器”;
OpenVPN 不能进内核,是因为它本质上是一个“需要人类理解的连接系统”。