TLDR 一句话: 硬路由利用 nfqueue 把关键包的处理逻辑外包给软路由
硬路由在专用芯片加持下,网络处理上的稳定性与性能上限是远高于软路由的,但我们很多人还是选择软路由当主力路由,不过是因为 x86 系统特别灵活,玩法很多。但仔细分析网络里的各个流程就可以发现,无论是软硬路由,灵活玩法大多来自于对各连接建立的包的处理,即 linux 里面的 iptables/nftables nat 表里的那些包。软硬路由都通过 cpu 处理这些包,其余的绝大部分包硬路由走专用芯片,软路由用 cpu 硬扛。
现在路由器大多基于 linux, linux 里面有各叫 nfqueue 的东西,可以把 iptables/nftables 里面感兴趣的包发到用户态进程里面,然后用户态可以进行一些操作,比如通过、丢包、拒绝、打 mark 、SNAT/DNAT. 但硬路由上由于 arm/mips 架构难搞、cpu 内存紧张等原因,这个机制像螺蛳壳里做道场,很鸡肋。
所以我在想是不是能在路由器上写个最轻量化的 nfqueue-agent, 把所有收到的包通过 tcp 转发到软路由的用户态 nfqueue-controller ,然后在 x86 上就可以 java/golang/python 爱怎么玩都行了?
应用场景:
ip 段分流/wireguard/zerotier
静态 ip 段路由表管理挺繁,要是 BGP 级别的话,ip 段文件不小,很多老古董 nand 甚至存不下。复杂一点的动态路由要搭建 bird/frr 服务,很麻烦。而我的方案里,nfqueue-controller 可以根据包的内容直接给包打上 mark, 再通过策略路由就很简单实现了分流。x86 可以搭建 wireguard/zerotier ,灵活度有保证。
无污染 dns 服务/fakedns/根据域名分流
传统域名分流很多是搞 ipset/nftables set ,要是路由器内核不支持就很难搞。nfqueue-controller 可以强行把所有 udp53 的包通过 mark 路由到自己 x86 节点,自己走 doh/dot. 也可以把 fakedns/vpn 的 IP 段通过 mark 路由到自己节点.根据请求域名的判断可以在 x86 端用户态维护一个 ipset,在下一次 tcp 请求中自动分流。
fullcone nat
可以把硬路由器自己的 nftables/iptables masquerade 都干掉,在 nfqueue 里进行 snat/dnat.不过这个我不太确定会和 linux conntrack 系统有什么化学反应
multiwan 负载均衡
用户态控制逻辑,想怎么分配就怎么分配
软路由节点 down 后 fallback
一旦硬路由上的 nfqueue agent 发现软路由超时未回复,立刻断开 nfqueue 绑定, 则所有网络设置恢复到单硬路由状态,不会引起断网。
大量新连接、路由表很长很复杂
这时候每个新连接的包都要经过网络给 controller 处理,可能会造成一些压力,不过可以在硬路由里利用 nftables 里面自定义 set/map 的功能可以缓存处理结果 mark ,例如连接五元组 30 分钟有效期内复用上次的 mark. 如果路由器只有 iptables 且没有 ipset, 也可以在路由器的 nfqueue-agent 里缓存结果。 不需要所有的都经过控制服务器,
这样只要支持 nfqueue 的硬路由器有可能这样来控制,可能很多官方固件也能玩,有点 sdn 的意思。
实现需要的具体工作:
agent: 收到什么就转发什么,类似 socat , 只不过是 netlink socket -> tcp socket.
controller: 用户态的 firewall 处理逻辑,最好是能复用 nftables/iptables 的语法与代码,这样学习、迁移成本更低,但把内核的代码在用户态用上应该是非常难的。或者把这个封装成 python/golang/java 库,用户可以写简单脚本控制, 也可以让社区继续发挥。
大家看看价值与可行性如何?
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.