基本原理¶
QRE 的目标是让用户侧只管理一个 profile 和一个 qre-tool 进程,而把握手、会话派生、内核状态和共享端口分流封装在工具与 kernel module 中。
组件¶
| 组件 | 作用 |
|---|---|
qre-tool |
用户态控制工具。负责配置解析、生命周期、daemon 模式、诊断、会话安装和调试命令。 |
qred@.service |
systemd 模板。实际执行 qre-tool daemon %i。 |
qre.ko |
Linux kernel module。负责 QRE 设备、封装/解封装、会话表、CID 控制和统计。 |
qre-ebpf |
共享 UDP 端口场景下的 SO_REUSEPORT 分流程序。 |
| REALITY/QUIC 控制路径 | 建立伪装握手,派生 QUIC 数据通道 key,把内核可用的 session 安装到 qre.ko。 |
控制面和数据面¶
启动 profile 时,qre-tool 依次完成:
- 读取全局配置和接口 profile。
- 加载
qre.ko,除非通过环境变量禁用。 - 通过 Generic Netlink 把 profile 同步到
qre.ko。 - 通过 rtnetlink 设置 QRE 设备地址和 link 状态。
- 进入 server 或 client 的持久控制面。
- 握手成功后,把会话 key、CID、packet number 和 underlay tuple 安装到内核。
安装会话后,数据包进入内核快速路径。用户态继续负责重连、重载、ready file、共享端口 loader 生命周期和退出清理。
REALITY 关系¶
服务端配置:
Dest = www.example.com:443
ServerName = www.example.com
RealityPrivateKey = ...
RealityShortIds = 0123456789abcdef
RealityMaxTimeDiff = 120
客户端配置:
Endpoint = 203.0.113.10:443
ServerName = www.example.com
RealityPublicKey = ...
RealityShortId = 0123456789abcdef
客户端连接 Endpoint,但握手中使用 ServerName 和服务端公钥。服务端用 RealityPrivateKey 验证客户端,检查 short id、时间窗口和 SNI。通过验证后,双方派生 QRE 数据通道需要的 QUIC key。
Dest 不等于 QRE 服务端地址。它是服务端用于伪装行为和 Dest profile 的目标源站。
CID 分流¶
QRE 使用连接 ID 作为内核和 eBPF 分流的稳定键:
install-session和update-session成功后会自动adopt-cid。adopt-cid把ConnectionId加入内核 CID 控制表。- 注册了
QRE_CID_ROUTESBPF map 时,内核会把已采用和后续采用的 CID 同步到 map。 - 共享端口 eBPF 程序根据短头包中的 routed CID,把包送到用户态 fallback socket 或内核 socket。
routed CID 长度默认来自库常量,调试命令允许通过 RoutedCidLen=17..20 覆盖。
共享端口¶
服务端常见需求是让普通 TLS passthrough、REALITY 握手和已安装 QRE 数据流共享一个公网端口。QRE 的共享端口路径包含三层:
- 用户态握手/fallback socket,负责接收新 REALITY/QUIC 握手和非 QRE fallback。
- 内核 slot UDP socket,供 eBPF 把已采用 CID 的数据流导向
qre.ko。 QRE_SOCKETS与QRE_CID_ROUTESBPF map,供qre_reuseport_demux查询。
生产路径由 qre-tool daemon <server-profile> 持有。shared-port-loader、shared-port-loader-check 和 shared-port-session-demo 是调试或验收命令。
SSLPreRead fallback¶
[SSLPreRead "..."] 是全局配置中的低优先级 TCP passthrough 规则。它只处理不是有效 QRE REALITY 握手的普通 TLS 流量:
[SSLPreRead "web-a"]
Listen = 0.0.0.0:443
SNI = cdn-a.example.com
Upstream = 127.0.0.1:8443
[SSLPreRead "default"]
Listen = 0.0.0.0:443
SNI = default
Upstream = 127.0.0.1:4430
它读取 ClientHello SNI,按 Listen + SNI 或 Listen + default 选择 Upstream,然后透明转发字节。它不终止 TLS,不安装 QRE 会话,也不参与 REALITY 验证。
同端口多租户¶
同一个 Listen 可以服务多个 profile。规则是:
- 每个租户仍然有自己的
/etc/qre/dev/<profile>.conf。 - sibling server profile 可以共享
Listen、ServerName和Dest。 - 每个 profile 保留自己的
Device、Address、hooks、routes 和RealityShortIds。 - 多个 server profile 也可以共享
Listen,但使用不同ServerName。 - 分流键是
Listen、ServerName和认证后的 short id。
这让一个公网端口可以同时承载多个 QRE 设备或租户。