我试图让系统解析为远程 DNS 缓存服务器(我知道它不是这样做的)。我添加了将 net.ipv4.conf.br0.route_localnet 更改为 1 并添加了以下 nftable 规则:
table ip nat {
chain prerouting {
type nat hook prerouting priority 100; policy accept;
iif "br0" udp dport 53 counter packets 6 bytes 366 dnat to 127.0.0.53
}
chain postrouting {
type nat hook postrouting priority -100; policy accept;
ip saddr 127.0.0.53 oif "br0" counter packets 0 bytes 0 snat to 192.168.1.2
}
}
预路由规则似乎有效,因为有数据包符合规则。但是没有数据包从主机发出,问题出在哪里?
如何将 DNS 请求从 192.168.1.0/24 重定向到托管在 192.168.1.2 的 lo 设备上(IP 为 127.0.0.53)的 systemd-resolved?
答案1
systemd-resolved
绑定到lo
接口:
# ss -aunp src == 127.0.0.53 sport == 53
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=44157,fd=17))
net.ipv4.conf.br0.route_localnet=1
即使将路由应用于接口上设置的路由,这也将限制可用的路由lo
:
$ ip -4 route show table all dev lo
broadcast 127.0.0.0 table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 table local proto kernel scope link src 127.0.0.1
没有一个会匹配。
源地址需要更改。虽然很少使用的type nat hook input
链类型允许在应用程序收到源地址之前更改源地址,但已经太晚了:这种情况发生在路由完成并且数据包已被丢弃之后。因此,有状态 NAT 无法处理这种情况。
可以使用代理来实现这一点(删除所有特定的 nat 设置后)。下面是使用代理的示例socat
.socat
由于不是专用应用程序,因此特别需要注意的是 UDP。
TCP 处理(OP 忘记了 DNS 也使用 TCP)
socat TCP4-LISTEN:53,bind=192.168.1.2,reuseaddr,fork TCP4:127.0.0.53:53
无法绑定,
IN_ADDR_ANY
因为 127.0.0.53:53 已绑定,因此绑定到 OP 提供的地址(出于错误的原因):192.168.1.2。除此之外,它非常简单。UDP 处理
socat -T 20 UDP4-LISTEN:53,bind=192.168.1.2,reuseaddr,fork UDP4:127.0.0.53:53
之所以设置 20 秒超时,是因为
socat
在收到单个 UDP 数据包应答后无法立即告知其停止,并且所有分叉socat
命令会随着时间的推移不断累积。虽然在这种情况下 UDP 不必绑定到地址,但使用 UDP 绑定到地址可以避免与多宿主相关的警告,也不需要使用
IP_PKTINFO
套接字选项。