最近把 OpenWRT 网关上的分流工具从 Clash 切换到了 sing-box ,顺带开始了解基于 TUN 的透明代理配置。目前遇到的一个问题是,局域网内的 DNS 请求并没有被正确地路由/转发进 sing-box 的 DNS 模块。
具体的情况有点复杂。因为需要让家里运行着 PT 的 NAS 这类的设备不被透明代理,所以在配置 TUN 时并没有使用 auto route,而是自己编写了 nftables
规则和对应的 ip rule
/ip route
策略路由,将需要代理的设备的流量标上一个特定的 fwmark ,再将标记的流量策略路由到 sing-box 的 TUN 网卡 tun0 。简化后的设置类似这样:
# 在 nftables 的 prerouting 阶段标记需要被代理的流量:
type filter hook prerouting priority mangle - 1; policy accept;
# 1. 需要直连的设备 MAC 被提前存在 direct_macs set 中,不做额外处理直接放行
ether saddr @direct_macs counter return
# 2. 剩余的来自 LAN 的流量均需要代理,标记为 $tun_mark (0x02)
iifname $lan_devices counter meta mark set $tun_mark
之后配置策略路由:
# 将被标记了 tun_mark 的流量查 tun_table 表路由至 tun_dev
ip route replace default dev ${tun_dev} table ${tun_table}
ip rule add fwmark ${tun_mark} table ${tun_table}
至此整个系统可以正常工作了。但奇怪的是,只有指定了 DNS 服务器为非网关地址 (≠ 192.168.50.1) 的局域网内 DNS 请求才会被转发进 TUN ,而默认的、DNS 服务器地址为 192.168.50.1 的 DNS 请求并没有被 sing-box 看到,而是仍由监听在网关 53 端口的 dnsmasq 处理:
# 在局域网内的任一台被透明代理的设备上:
nslookup google.com # 这条查询会被 dnsmasq 接收
nslookup google.com 1.1.1.1 # 这条查询才会被正确地路由进 sing-box 的 TUN 设备
请问大家是不是我配置的策略路由在哪里出问题?多谢
按照 @pagxir #5, #7 的回复,将 DNS 请求 DNAT 到 TUN 对应的网段后,这些数据包就被交由 FORWARD chain 处理从而能正确转发到 TUN 设备了。具体的修改如下:
# 1. 在 prerouting chain 标记需要被代理的 DNS 数据包
type filter hook prerouting priority mangle - 1; policy accept;
iifname $lan_devices meta l4proto {tcp, udp} th dport 53 counter meta mark set $dns_mark return
# 我的 TUN 地址是 172.19.0.1/24; fdfe:dcba:9876::1/126
# 为防止被路由至 INPUT chain,将地址 +1
define tun_route_ip = 172.19.0.2
define tun_route_ip6 = fdfe:dcba:9876::2
# 2. 在 nat chain 将被标记的数据包 DNAT 到 TUN 的网段上
type nat hook prerouting priority dstnat - 1; policy accept;
meta mark $dns_mark dnat ip to $tun_route_ip
meta mark $dns_mark dnat ip6 to $tun_route_ip6
感谢各位大佬~
完整的 nftables
代码在 99-sing-box.nft#L65-L83,需要配合相应的服务启动和停止脚本来配置策略路由。谨供遇到同样困扰的朋友们参考~
1
CrazyRundong OP 目前的临时解决方案是在网关 sing-box 上再开一个 TProxy 端口,借助 TProxy 可以处理 UDP 请求的特性,把来自 LAN 的 TCP/UDP 53 流量通过 nftables 规则 TProxy 到这个端口。但感觉还是搞得太繁琐了,应该没必要这么麻烦
``` # 增加了一条 nftables 规则来 TProxy 来自局域网的 DNS 请求 iifname $lan_devices meta l4proto {tcp, udp} th dport 53 counter meta mark set $tproxy_mark tproxy to :$tproxy_port ``` (需要配置对应的额外策略路由) ``` ip route replace local default dev lo table ${tproxy_table} ip rule add fwmark ${tproxy_mark} table ${tproxy_table} ``` |
2
EyebrowsWhite 2023-12-10 18:54:30 +08:00
应该因为你的 dnsmasq 占用了 53 端口,`ss -ulnp | grep 53`确认一下,如果不用 dnsmasq ,就把它关了,然后 sing-box 的 DNS 监听端口改为 53
|
3
CrazyRundong OP @EyebrowsWhite 目前仍然需要 dnsmasq 监听在 53 端口来处理没被代理的设备的 DNS 请求,以及托管局域网里的一些域名映射规则。sing-box 似乎默认是没有 DNS 监听端口的,不像 Clash 。我在想能不能只开一个 TUN 、不用其他端口配置就能把 DNS 给处理好了
|
4
lookookok 2023-12-10 19:19:23 +08:00
不是太懂内核网络处理,盲猜是不是你这个策略只应用于转发数据包,而入站数据包是不是还要单独设置策略路由?
还有个折中的办法是可在 op web 设置中,指定的 dnsmasq 作为客户端源查询端口,给这个端口出站做策略走 tun ,比再来个 TProxy 简单些。 |
5
pagxir 2023-12-10 20:55:45 +08:00
走 tun 前提需要 forward ,很明显,你这个并不需要 forward ,而是走 input 链的。所以你需要要执行以下 DNAT ,使得报文走 forward 链。
|
6
CrazyRundong OP @lookookok 我的理解是 prerouting 发生在路由之前,也就是说 prerouting mangle 里打的 fwmark 是能够同时覆盖入站和转发的,参考 https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg
@pagxir 多谢大佬提醒,具体是指在 prerouting nat 里将 DNS 包 DNAT 到 TUN 的地址吗?我试试看 |
7
pagxir 2023-12-10 21:37:49 +08:00
@CrazyRundong 假设你 tun 的 IP 是 10.111.9.11/24, 那么你可以-j DNAT --to 10.111.9.222, 那样很自然就需要 forward 到 tun 出去了。(注意不能 -j DNAT --to 10.111.9.11, 那样还是会走 input 的)
|
8
CrazyRundong OP @pagxir 哈哈理解了,解释得很清楚!刚刚还在疑惑如果 DNAT 到 TUN 地址会不会又回环到 INPUT chain, 这么一说就明白了
|
9
kingboy9525 2023-12-11 13:36:35 +08:00
@CrazyRundong 请问有完整的 nft 可以参考一下吗?谢谢
|
10
CrazyRundong OP |
11
Kobayashi 2023-12-12 11:58:14 +08:00
让 sing-box DNS 监听在非 53 口,在 dnsmasq 里配置其为上游呢?
|
12
CrazyRundong OP @Kobayashi #11 应该也可以!就是不知道 sing-box 的哪种入站类型可以直接接收处理 DNS 请求
|
13
jacky4231 350 天前
楼主,我在 openwrt23.5 上直接安装了 sing-box 1.8.0 ,自己写了 josn ,用 tun 模式,可以连通,但是不知为何下载速度测试只有 250 左右,家里是千兆的网络。本人小白,能否将自定义 nft 规则给个完整的,并且告知如何导入?多谢了!
|
14
CrazyRundong OP @jacky4231 #13 在主帖的第二条附言有完整链接哈
|
15
jacky4231 350 天前
@CrazyRundong 感谢回复,我再试试
|
16
jacky4231 340 天前 via Android
大佬,能否帮忙写一下 tproxy 的 init.d 和 nft 配置文件?小白一个,tun 模式网速太低了,感激不尽,📭[email protected]
|
17
CrazyRundong OP @jacky4231 #16 我没有使用 sing-box + TProxy 的计划。但是我之前的 Clash 分流是通过 TProxy 实现的,你可以参考一下 https://github.com/lirundong/homelab-infra/blob/master/openwrt-builder/files/etc/init.d/clash.skip
另外,我这边观察到的 sing-box TUN 的网速足够跑满千兆下行 + 200M 上行,所以你观察到的网速低不一定是 sing-box TUN 的锅 |
18
jacky4231 310 天前
@CrazyRundong 新年快乐!能给下客户端配置文件样本吗,是不是我的配置文件有问题?多谢!
|
19
journalist 310 天前
我的 tun 接口不是在本机应该怎样修改呢,具体来说网关是 192.168.1.1 ,tun 在 192.168.1.2
|
20
CrazyRundong OP @jacky4231 #18 sing-box 配置文件可以通过 https://github.com/lirundong/homelab-infra/blob/master/conf-gen/generate.py 脚本自动生成,其源文件是 https://github.com/lirundong/homelab-infra/blob/93352db/conf-gen/source.yaml#L532-L617
请不要做伸手党或直接留邮箱,这对社区讨论和知识共享无益,我也没有义务帮你写配置文件 |
21
journalist 308 天前
感谢!我现在已经跑通了。
ip route replace default via 192.168.1.2 dev br-lan table ${tun_table} 有一个问题就是 type nat hook prerouting priority dstnat - 1; policy accept; 这里会报错 Could not process rule: Not supported 。我就把 dns dnat 去掉了,用 openwrt uci 自带的端口转发功能。 |
22
garryforreg420 231 天前
用 sing-box 的 direct 开一个端口来当 dns 服务器不就行了,干嘛搞这么复杂.
op 的 dnsmasq 关了或者换个端口,sing-box 配置 inbound direct 53,主路由或者 op 的 dhcp 上把下发 dns 服务器指向 sing-box 开放的地址即可。 |