从 OpenClash 到 dae:一个刷机老手的两天折腾记
2026 年 8 月,星期天。女朋友不在家,一个人,有大把时间。于是我想起一件盘算了很久的事:把路由器的代理方案,从 OpenClash 换到 dae。
事情是怎么开始的
这件事的起因,一半是技术判断,一半是”手痒”。
先说判断。我从 2017 年开始折腾路由器,那会儿还念高中,在闲鱼淘了台斐讯 K2。一开始用的甚至不是 OpenWrt——是 hanwckf 的 Padavan,华硕固件底子改的,又稳又省心。后来刷了潘多拉(PandoraBox),才算真正弄懂 OpenWrt 那套东西:内核、feeds、opkg,还有 Breed——刷不死鸟引导器,只要 Breed 还在,刷机刷得再烂都死不了。
快十年,手里的机器从 K2 换到 K2 Pro,再到现在的 360T7。软路由只在 N1 盒子上短暂玩过,主力一直是硬路由。插件则换了一茬又一茬:SSR、Passwall、OpenClash。
这套组合用着一直还行,但有两个问题慢慢积攒起来。一是架构越来越重——OpenClash 当代理,AdGuard Home 当广告过滤,两层各管一摊,总觉得哪里别扭。二是性能一直没打满——千兆宽带,日常上网只能跑到 700M。
所以当我在网上看到 dae 这个方案时,第一反应不是”要不要换”,而是”这值得认真评估一下”。它宣称的东西——eBPF、内核层分流、真直连——恰好命中了我那两个痛点。
为什么要翻墙
先把这事儿说透。为什么要翻墙?
不是为了什么不可告人的东西。是信息、学术、工具、内容——一个搞技术的,GitHub 打不开、Google 搜不了、一堆开发文档在墙外,这日子没法过。我高中那会儿想看的教程、想下的软件、想进的学习网站,一堆在墙外。这不只是我的需求,是一代人的需求。
从 2003 年金盾工程立项起,这堵墙和绕墙的人就一直在玩猫鼠游戏:
- 早期是免费代理、Tor——反复被墙;
- 后来是 PPTP/L2TP/OpenVPN——2012 到 2015 年被 DPI(深度包检测)识别封杀;
- 2012 年,Shadowsocks 出现。它把流量加密成随机字节流,看起来就是普通流量,优雅地躲过特征检测,一夜爆红;
- 2015 年大清洗,ss 的握手特征被识别,于是 SSR(ShadowsocksR)加上了混淆协议,猫鼠游戏升级;
- 2015 年 V2Ray/VMess 带着时间校验、动态端口杀进来;
- 2018 年 Trojan 更进一步——直接伪装成一个正常的 HTTPS 网站,你连过去它给你看网页,你带上钥匙它就是隧道,正面刚”443 非 TLS 就封”的策略;
- 2018 年 Clash 带着 YAML 规则和订阅管理来了,机场生态爆发,使用门槛骤降;
- 2022 年 REALITY 借真实网站的 TLS 指纹,几乎无法检测;
- 再到 2023 年的 sing-box、dae……
但所有这些,到了路由器这一层,都只是”内核”。你看到的插件——SSR Plus、Passwall、OpenClash——都是壳。壳决定体验,内核决定能力。换插件不叫升级,换内核才是。
换壳记:从 SSR 到 OpenClash
我第一次用 SSR 的时候,还在高中。那时候的插件就是 luci-app-ssr-plus 那一类,简单、够用。后来为什么一路换?
两个原因。
第一个:节点支持的协议不一样。SSR 毕竟年代久远,它的安全性和抗检测能力都偏低了。机场的节点协议在升级,老插件接不住新协议,你不换插件,节点都没法用。
第二个,也是更本质的:不同插件的规则可定义范围不一样。核心功能——翻墙上网——大家都能做,区别在于你能对流量做多精细的控制。SSR Plus 的规则就那么几板斧,Passwall 灵活一些、能挂多个核心(v2ray/xray),而 OpenClash 的自定义程度最高:YAML 规则、规则集、节点策略组、订阅管理,几乎什么都能配。
所以我的路线图是:SSR → Passwall → OpenClash。一路往上,本质是在换”壳”,换更自由的控制面板。
700M 的税:OpenClash 的代价
OpenClash 好用,但那个”别扭”感,我后来想明白了。
我原来的架构是分层:OpenClash 当代理层,AdGuard Home 当广告过滤层。但两层太复杂,后来我把广告过滤直接塞进了 OpenClash 的代理规则里——图一个少一层。
代价很快就显现。千兆宽带,日常上网只能跑到 700M。而且 MT7981 这颗 CPU 开始发热:待机 60 度,WiFi 模块 55 度;满速跑代理,CPU 能冲到 70 度,负载飙到 2 甚至接近 3。
问题出在哪?
OpenClash 是 Clash/Mihomo 内核的用户态方案。TUN 模式下,流量路径是这样的:
设备 → 网卡驱动 → 内核协议栈 → TUN 虚拟网卡 → Clash 进程(用户态) → 分流判定 + 代理/直连处理 → 内核协议栈 → 网线出去注意最后那步:即使是”直连”的国内流量,也要从内核态切到用户态(Clash 进程),处理完再切回内核态发出去。每个包两次上下文切换。我把广告过滤塞进规则后,国内流量也得过 Clash 这一层——那 300M 的差距,就是用户态处理的税。
这不是 Clash 的错,是用户态方案的宿命:你的分流逻辑跑在用户态,流量就得进用户态。
遇见 dae:eBPF 和”真直连”
dae 是 daeuniverse 的作品。它的作者 mzz2017 之前做了 v2rayA——v2ray-core 的 Web 界面,用 iptables 分流。做久了,他看到了一个天花板:任何用户态代理,连”直连”流量都要经过用户态处理一遍。这是架构性的浪费,不是调优能救的。
他的解法是换个赛道:用 eBPF 把分流程序写进 Linux 内核的 tc(traffic control)挂载点,在流量进入 TCP/IP 协议栈之前就完成分流。eBPF 程序跑在内核态,没有上下文切换。
直连流量是这样走的:
设备 → 网卡驱动 → tc 挂载点(eBPF 分流判定) ├─ 直连 → 内核 L3 路由直接转发 → 网线出去 ← 零用户态开销 └─ 代理 → 重定向到 dae 的 tproxy 端口 → dae 用户态加密 → 网线出去关键在”Real Direct”(真直连):直连流量在内核层就拐弯了,Linux 变成一台纯交换机/路由器。mzz2017 自己在文档里写:“以 benchmark 来看,dae 的直连性能和其他代理程序相比就像个怪物。“隔着屏幕都能看见那点得意。
除了分流,还有两个设计细节值得玩味:
- 进程匹配:Clash 要扫 /proc 文件系统才能知道一个连接属于哪个进程,可能要几十毫秒;dae 用 eBPF 在 cgroupv2 挂载点监听系统调用,直接读进程控制块,快一个量级。
- 域名匹配:dae 劫持 DNS 请求,建立”域名 → IP”的映射表。所以它的 DNS 处理必须自己来——这也是为什么配置里 dnsmasq 的流量要 must_direct(强制直连),否则 DNS 不过 dae,域名分流就失效。
但架构没有白来的好处。eBPF 的性能来自内核,代价也是内核:要内核 5.17+,要 BTF 调试信息,要 veth 虚拟网卡,要一堆 CONFIG 选项。桌面 Linux 默认开着,嵌入式固件(OpenWRT/Armbian)默认关掉。
换句话说:dae 把性能做进了内核,把税留给了固件。而我的 360T7 恰好装着 Yuzhii 的 fixed-parts U-Boot——这是整个迁移里唯一真正需要认真对待的约束。
迁移:两天,15 个坑,一次关键判断
先说清楚我的方法论:这件事我没打算”试试看”,而是先列约束,再逐条验证。迁移的第一条约束就很硬——Yuzhii 的 U-Boot 只认 FIT 格式。
约束之一:分区表是硬门槛
Yuzhii 的 U-Boot 从闪存固定偏移读原始 FIT 镜像(魔数 d00dfeed),不解析 UBI 卷:
| 格式 | 特征 | 能不能启动 |
|---|---|---|
| FIT (.itb) | 魔数在偏移 0 | ✅ |
| sysupgrade (.bin) | 魔数在偏移 0x800 | ❌ |
| UBI factory (.bin) | 魔数 UBI# | ❌ |
官方 ImmortalWrt 固件全按 UBI 分区布局组织,分区表和 Yuzhii 的 U-Boot 对不上——跟手机刷机一个道理,分区表不兼容,镜像再新也刷不进去。
这条约束我在动手前就确认过,所以固件选择从一开始就没走偏。但强刷不兼容固件这件事,我确实验证过一次——不是为了试错,是为了确证”哪些固件真的不能用”。结果卡红灯,SSH 全断。对很多人这是噩梦,对我来说只是流程里的一步:进 U-Boot TFTP 模式,推 initramfs-recovery.itb 进去,十分钟救回来。
这里要纠正一个说法:这不叫变砖。
什么叫真正的砖?我从安卓 2.3.2 刷到 4.0.4、再刷到 4.4.4 那一代人,见过真正的砖:连引导器都进不去,没有任何恢复模式。手机没有 fastboot 就是黑砖,只能靠高通 9008 厂商模式串口救;路由器连 Breed/U-Boot 都进不去,就得拆壳上 TTL 串口线,看 bootlog,手搓救砖。
卡开机?U-Boot 还在、TFTP 还能进?那只是小场面,跟换轮胎差不多。
约束之二:kmod-veth 必须编译期解决
dae 启动时要创建 veth 虚拟网卡对,内核缺 CONFIG_VETH 直接报 fatal。这条约束有个隐蔽的点:kaslana(我此前维护的自编译固件)用的 SNAPSHOT 内核,vermagic 和官方仓库的 kmod 包对不上,apk add kmod-veth 直接”No such package”。
根本原因:内核和 kmod 包不是一起编译的,ABI 签名不一致。所以这条只能靠”编译时把 kmod-veth 编进固件”解决,事后装不了——这也是我后来去跑自编译的动机之一:既然要动内核,干脆验证一遍构建链路。
约束之三:BTF 与 eBPF 工具链
自编译那两天,GitHub Actions 跑了 11 次、12 小时,坑确实多,但复盘下来最值得写的有两个,都指向构建系统本身的隐蔽性:
一个是通配符陷阱。我用 for f in target/linux/generic/config-* 循环改内核配置,结果 config-* 把 config-filter 也匹配进去了,排序后版本号解析成 “filter”,BTF 选项全写进了错误的文件。编译了两遍都”成功”,但 BTF 没生成,daed 照样崩。这类 bug 不写进文章没人信,但它就是真实存在的。
另一个是静默剔除。@HAS_BPF_TOOLCHAIN 是 Kconfig 条件,不满足时 make defconfig 会静默移除 daed 包,一个警告都没有。得开 CONFIG_DEVEL=y + CONFIG_BPF_TOOLCHAIN_HOST=y 才看得到。
关键判断:为什么自编译本身是个伪需求
两天泥潭的尽头,不是”终于编译成功了”,而是一个更值钱的发现——自编译这个前提,本身站不住。
我在 6.12 内核上跑 daed,崩在:
program of this type cannot use helper bpf_get_current_task#35根因是内核 6.12 的 sockops 程序不支持 bpf_get_current_task helper。我当时的第一反应是”那我编译一个带正确配置的内核”。这是惯性思维。
停下来问了一句:官方 SNAPSHOT 用什么内核? 答案是 master = 6.18。再验证一句:6.18 支持这个 helper 吗?支持。那结论就清楚了——官方固件已经满足 dae 的全部运行条件,缺的只是 BTF 数据和几个 kmod 包。而 vmlinux-btf 走 CO-RE 机制跨版本兼容,6.12 的 BTF 数据在 6.18 上也能用。
于是最终的迁移路径短得反常识:刷官方 SNAPSHOT → 加 cooluc 第三方源 → apk add vmlinux-btf daed luci-app-daed → 5 分钟装完。
重新审视最初的判断:我为什么想自编译?因为想要完全可控的内核配置。但当官方固件已经满足全部硬性约束时,这个前提就塌了。结论不是”我白编了两天”,而是”我用了最硬核的方式,验证了一条其实更短的路径”。这种验证本身是有价值的——它排除了”官方固件不行,必须自编译”这个假设。
现在是真舒服
迁移完成,一切正常。逐项对照最初的痛点:
- 国内直连:恢复千兆满速。eBPF 的内核分流,国内流量不进用户态,那 300M 的税没了。
- 代理流量:说实话,国外网速没有提升,还是 150M 左右。原因很实在:代理速度的瓶颈在加密和线路,不在分流机制——不管 eBPF 还是 TUN,代理流量最终都要进用户态做加密,CPU 算力到头了就是那么多。这点得说清楚,不吹。
- 广告过滤:拆出来单独跑了 AdBlock Fast(adblock 的轻量版),不再塞进代理规则。分层又回来了,但这次没有性能税,因为广告过滤在代理之外。
- 温度:待机 60 度,满速代理 70 度,比 OpenClash 时代舒服。
开发者视角:mzz2017 的取舍
写到最后,想说点站在开发者角度的话。
mzz2017 先是做了 v2rayA,然后抛弃了它。不是不好,是看到了天花板。他审视市面上的方案:
- Clash:用户态做一切,直连流量也交税;
- Fake IP:有 DNS 缓存污染的老问题;
- iptables/nftables:挂在 netfilter 上,位置太靠后,分流已经晚了;
- 域名嗅探:只能嗅 TLS/HTTP。
他的想法很直接:为什么不能在最早的路径上就把流量分了?eBPF 给了他答案。代价是内核要求高,用户侧适配成本大——也就是我这两天验证的全部内容。
dae 适合谁?适合软路由玩家、愿意折腾内核配置的人、在乎直连性能和资源占用的人。它不适合纯小白——底层约束太多,一个 kmod-veth 就能劝退一片。
但换个角度想:dae 把性能做进内核,是把”性能税”从运行时转移到了部署时。 运行的时候快得飞起,部署的时候要过五关斩六将。这个交易划不划算,看你是哪种用户。
附录:给想迁移的人
- 固件:官方 SNAPSHOT(内核 6.18)即可,或 Wei.G 上 T7 非 UBI 编译的固件
- kmod-veth:必须编译期包含,事后装不上(vermagic 不匹配)
- BTF:确认 CONFIG_DEBUG_INFO_BTF=y,否则 daed 无法运行;缺的话装 vmlinux-btf
- 分区变体:Yuzhii U-Boot 只认非 UBI,永远选非 UBI 固件
- 恢复:卡开机就 U-Boot TFTP 推 initramfs-recovery.itb,十分钟的事
- 包管理:25.12 用 apk,不是 opkg
- 配置:全在 /etc/daed/wing.db,SQLite 可以直接操作
- 订阅转换:Clash YAML 需转 URI,用 luci-app-daede 或 Python 脚本
- 接口:必须设 br-lan,不是 wan
- 广告过滤:daed 不带,用 AdBlock Fast 之类单独跑
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!







