Skip to content

Linux eBPF

在 Linux 上,增强模式把 eBPF 程序挂到 cgroup v2 的 socket hook 上。任何程序发起连接时,内核已经知道 它属于哪个进程、要去哪里,Specola 据此按你的规则路由。不创建 TUN 设备,也不修改路由表。

系统要求

  • Linux 5.17 或更新;
  • cgroup v2 挂载在 /sys/fs/cgroup
  • 内核 BTF(/sys/kernel/btf/vmlinux);
  • root 权限,用于加载和挂载 BPF 程序。

检查:

bash
uname -r                                  # 5.17 或更新
stat -fc %T /sys/fs/cgroup                # cgroup2fs
test -r /sys/kernel/btf/vmlinux && echo BTF ok

当前的 Arch Linux(包括 Omarchy)、Fedora、Ubuntu 24.04+ 和 Debian 12+ 内核都满足这三项。在容器内, 即使是 root 通常也无法加载 BPF 或挂载 cgroup 程序。

配置

toml
[general]
route-mode = "rule"
port = 7890
protocols = "mixed"

[[proxy]]
name = "office"
type = "http"
server = "proxy.example.com"
port = 8080

[rule]
list = [
  "PROCESS-NAME,git-remote-http,office",
  "PROCESS-NAME,cargo,office",
  "DOMAIN-SUFFIX,corp.example.com,office",
  "IP-CIDR,10.0.0.0/8,DIRECT,no-resolve",
  "FINAL,DIRECT",
]

[dns.tun]
mode = "fake-ip"

[enhanced-mode]
enable = true
type = "ebpf"
ip-version = "ipv4"

[enhanced-mode.ebpf]
process-routing = true

本地端口必须保持开启(port > 0):被重定向的连接通过它交给 Core。[dns.tun] 决定 Core 如何应答 被接管进程的 DNS 查询;默认就是 Fake-IP,所以这个表可以省略。

字段

字段默认值说明
[enhanced-mode] ip-version"ipv4"eBPF 后端接管 IPv4,IPv6 流量会绕过
[enhanced-mode.ebpf] process-routingfalse为连接关联进程;规则中使用 PROCESS-* 时设为 true
[enhanced-mode.ebpf] unmatched-traffic"direct"为兼容旧配置保留;未命中的流量现在总是按 FINAL 处理

运行

先以普通用户校验,再用 root 启动:

bash
specola-core -t --config my.toml
sudo specola-core --config my.toml

启动成功时日志包含:

text
Linux IPv4 process proxy started with cgroup eBPF socket redirection (IPv6 bypassed)

Ctrl+CSIGTERM 停止,Core 会卸载它挂载的程序。使用 sudo 时,--config 中只写文件名 仍会在你自己的 ~/.config/specola/profiles/ 中查找。

长期运行请使用 systemd 服务,完整的 unit 文件见《在 Omarchy 上使用 Specola》

一条连接如何被决定

每一条新的 TCP 连接或 UDP 发送,在内核中按以下顺序处理:

  1. Core 自己和 Specola UI 的 socket 始终放行;
  2. 发往 53 端口的 DNS 查询交给 Core 的 DNS 模块;
  3. 回环、本机地址、私有和链路本地网段、组播和广播直接放行;
  4. 其余连接与 Core 在 BPF map 中维护的候选列表比对:规则中的进程名、IP 规则的网段、DNS 为带域名 规则的域名返回的地址,以及当前的 FINAL
  5. 不是候选的连接在内核中按 FINAL 处理。FINAL,DIRECT 时它保留原始 socket,从不进入 Core;
  6. 候选连接被重定向到 Core 的本地端口,Core 按顺序执行完整规则列表,决定直连、拒绝,或经由所选的 代理或代理组连接。

这对规则意味着:

  • 精确的 PROCESS-NAME 可以在内核中预先检查;PROCESS-PATH、通配符和正则不行,会让更多连接绕经 Core。
  • 如果 FINAL 是代理或代理组,所有非本地连接都会经过 Core。
  • 修改规则只影响新连接,已建立的连接保持原有决定。
  • 自己走加密 DNS 的应用不会让 Core 看到域名,请用进程或 IP 规则匹配。

验证

bash
curl -sI https://example.com                   # 会出现在 Specola 连接日志中
sudo bpftool cgroup tree /sys/fs/cgroup         # 列出已挂载的程序

Core 停止后,这些程序会从 bpftool cgroup tree 中消失。

想在不改动真实程序的情况下测试进程规则,可以把一个可执行文件复制成规则期望的名字:

bash
cp /usr/bin/curl /tmp/cargo && /tmp/cargo -sI https://example.com   # 命中 PROCESS-NAME,cargo

排错

现象原因与处理
enhanced-mode.type=tun is not supported on Linux改用 type = "ebpf"
cgroup v2 is not mounted at /sys/fs/cgroup系统使用 cgroup v1 或非标准挂载点;启用统一 cgroup 层级
Operation not permitted没有以 root 运行,或容器、LSM 禁止了 BPF
进程规则始终不命中内核中的名字不同;用 cat /proc/<pid>/comm 查看(最多 15 个字符)
域名规则始终不命中应用使用自己的 DNS(DoH);改用进程或 IP 规则
IPv6 网站绕过了 Specola正常现象,后端只接管 IPv4。保持 [dns].ipv6 = false,让被接管的程序拿到 IPv4 应答
所有流量都经过 CoreFINAL 是代理,或路径/通配符规则让大部分连接成为候选