我正在尝试在隐藏在 NAT 路由器后面的一个网络上设置 PXE 引导(需要 TFTP)。
我的问题与网络上的许多其他问题相似,但我发现的所有答案都适用于带有 iptables 的 CentOS 7。我需要使用以 firewalld 和 nft 作为后端的 CentOS 8 来执行此操作。
无法对 TFTP 流量进行 NAT,因为 iptables 未将返回连接转发到客户端,尽管 TFTP 帮助程序创建了期望 https://unix.stackexchange.com/questions/579508/iptables-rules-to-forward-tftp-via-nat
这是我的简化网络图:
Outside NAT Inside NAT
10.0.10.10 10.0.10.11->192.168.1.1 192.168.1.2
TFTP server --------> NAT ---------> PXE/TFTP client
TFTP 不工作。使用 tcpdump,我看到 RRQ 消息从 192.168.1.2 成功传输到 10.0.10.10。响应到达路由器,但未正确 NAT 到达客户端。
我尝试了 sysctl net.netfilter.nf_contrack_helper 的两种设置(更改设置后重新启动):
# sysctl -a | grep conntrack_helper
net.netfilter.nf_conntrack_helper = 0
使用 nf_contrack_helper=0:
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
Initial RRQ:
14:02:27.842563 IP (tos 0x0, ttl 64, id 64642, offset 0, flags [DF], proto UDP (17), length 54)
192.168.1.2.36799 > 10.0.10.10.69: [udp sum ok] 26 RRQ "grub2/grubx64.efi" octet
Initial RRQ after NAT:
14:02:27.842619 IP (tos 0x0, ttl 63, id 64642, offset 0, flags [DF], proto UDP (17), length 54)
10.0.10.11.36799 > 10.0.10.10.69: [udp sum ok] 26 RRQ "grub2/grubx64.efi" octet
Response from TFTP server to NAT router:
14:02:27.857924 IP (tos 0x0, ttl 63, id 60000, offset 0, flags [none], proto UDP (17), length 544)
10.0.10.10.60702 > 10.0.10.11.36799: [udp sum ok] UDP, length 516
(repeated several times until timeout)
在 nf_contrack_helper=1 的情况下,传出的数据包甚至根本没有经过 NAT:
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
Initial RRQ:
14:02:27.842563 IP (tos 0x0, ttl 64, id 64642, offset 0, flags [DF], proto UDP (17), length 54)
192.168.1.2.36799 > 10.0.10.10.69: [udp sum ok] 26 RRQ "grub2/grubx64.efi" octet
(repeated several times until timeout)
都加载了 nf_*_tftp 助手(无论 nf_contrack_helper 设置如何):
# lsmod | grep tftp
nf_nat_tftp 16384 0
nf_conntrack_tftp 16384 3 nf_nat_tftp
nf_nat 36864 3 nf_nat_ipv6,nf_nat_ipv4,nf_nat_tftp
nf_conntrack 155648 10 nf_conntrack_ipv6,nf_conntrack_ipv4,nf_nat,nf_conntrack_tftp,nft_ct,nf_nat_ipv6,nf_nat_ipv4,nf_nat_tftp,nft_masq,nft_masq_ipv4
上面链接的一篇文章建议使用 iptables 进行以下操作(这是有道理的):
iptables -A PREROUTING -t raw -p udp --dport 69 -s 192.168.11.0/24 -d 172.16.0.0/16 -j CT --helper tftp
我将如何使用带有 nft 后端的 firewalld 进行等效操作。
更新:
firewalld 配置相当复杂,所以我只添加相关区域:
外部区域:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<source address="10.0.10.0/24"/>
<service name="tftp-client"/>
<service name="ssh"/>
<masquerade/>
</zone>
和内部区域:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<source address="192.168.1.0/24"/>
<service name="dhcp"/>
<service name="ssh"/>
<service name="dns"/>
<service name="tftp"/>
<masquerade/>
</zone>
注意:内部区域的化妆舞会是一个错误。我删除了它,但行为没有改变。
区域漂移被禁用。
更新 2:
要回答评论者的请求:
DHCP 配置
DHCP 服务器与 NAT 路由器(网络图中的 192.168.1.1)在同一系统上运行。它是标准 ISC DHCP,分发 IP 地址(作为固定地址;不涉及池)、掩码、网关、DNS 服务器等,以及 PXE Boot 下一个服务器和文件名选项。
这一切显然有效。tcpdump 显示客户端向服务器发送了正确的 RRQ 数据包。
响应返回到 NAT 路由器,但不会发送到 NAT 后侧。
有关 TFTP 如何工作以及它如何与 NAT 中断的详细信息
如果您了解 TFTP 协议,就很清楚发生了什么;我只是不知道如何使用 firewalld/nft/CentOS 8 来处理它。
从根本上说,问题在于 TFTP 协议以非标准方式使用 UDP 端口。在“标准”基于 UDP 的协议(例如 DNS)中,响应来自服务器侦听的同一端口。
Request: client:54321 -> server:53
Response: server:53 -> client:54321
(其中 54321 可以是客户端选择的任何随机临时端口号)。
NAT 匹配这些 IP 地址和端口以识别哪个响应属于哪个请求。
TFTP 的做法不同;响应不是来自端口 69,而是来自其他一些随机端口。
Request (RRQ): client54321 -> server:69
Response (Data): server:12345 -> client:54321
其中 54321 再次是客户端选择的随机临时端口,而 12345 是服务器选择的随机临时端口。
结果,标准 NAT 行为将找不到与源服务器匹配的连接:12345,并丢弃数据包。
此问题的解决方案涉及使用帮助程序 - 理解此怪癖的 nf_nat_tftp 内核模块。
我只是无法弄清楚如何使用 CentOS 8、nftables 和 firewalld 来实现这一点。
使用 nftables 的答案对我来说是完全可以接受的,只要它不违反任何防火墙规则。
不工作的原因
看来firewalld可能适合处理防火墙本地服务,而不是路由服务。
因此,当使用 OP 中的区域文件(仅显示规则,而不是此处的整个规则集)配置了 firewalld(在 CentOS 8 上)时, tftp设置将在最后添加这些 nft 规则:
这些规则永远不会匹配,因此是无用的:它们在输入路径中,而不是在正向路径中。
使用正在运行的防火墙,这些(盲目复制的)规则添加在正确的位置:在转发路径中,将使 TFTP 工作:
所以最后一个所谓的直接选项仍然是一个选项,所以一切都存储在firewalld的配置中。唉,文档有点误导:
不仔细阅读会认为通过接受nftables规则
FirewallBackend=nftables
会表现不同,但事实并非如此:无需进行更多测试,此“功能”记录在那里:
https://bugzilla.redhat.com/show_bug.cgi?id=1692964
在那里:
https://github.com/firewalld/firewalld/issues/555
直接规则仍然使用带有nftables后端的iptables 。CAVEAT 是关于规则评估的顺序。
在另一个表中处理这个
我不再认为使用firewall-cmd执行此操作有什么意义,它将在nftables规则中添加iptables规则。添加一个独立的表只会变得更干净。它只是在ip系列中,因为还将添加特定 IPv4 网络的过滤器(inet也可以)。
handletftp.nft
(要加载nft -f handletftp.nft
):由于表不同并且规则集永远不会被刷新,而是特定表被(原子地)删除并重新创建,这不会影响firewalld也不会影响它。
优先级无关紧要:在firewalld的链之前或之后遍历该链不会改变数据包的命运(仍在firewalld手中)。无论顺序如何,如果数据包被firewalld接受,它也将激活此流的帮助程序。
如果您选择使用nftables服务来加载此表,则必须对其进行编辑(例如:)
systemctl edit --full nftables
,因为除了加载一些可能不合适的默认规则外,它还会在停止或重新加载时刷新所有规则,从而中断firewalld。现在,TFTP 传输将起作用并激活特定的帮助程序,可以通过
conntrack
在传输期间运行两个命令来检查:上例中的第三个 NEW 条目实际上被标记为 RELATED(这是 tftp 助手的全部作用:期望某种类型的数据包将其视为相关),这将被防火墙接受。