AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 1042106
Accepted
Kevin Keane
Kevin Keane
Asked: 2020-11-11 15:02:22 +0800 CST2020-11-11 15:02:22 +0800 CST 2020-11-11 15:02:22 +0800 CST

CentOS 8 作为带有 nft 和 firewalld 的 NAT 路由器 - 如何让它通过 TFTP?

  • 772

我正在尝试在隐藏在 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 的答案对我来说是完全可以接受的,只要它不违反任何防火墙规则。

nftables firewalld tftp
  • 1 1 个回答
  • 3004 Views

1 个回答

  • Voted
  1. Best Answer
    A.B
    2020-11-13T17:27:01+08:002020-11-13T17:27:01+08:00

    不工作的原因

    看来firewalld可能适合处理防火墙本地服务,而不是路由服务。

    因此,当使用 OP 中的区域文件(仅显示规则,而不是此处的整个规则集)配置了 firewalld(在 CentOS 8 上)时, tftp设置将在最后添加这些 nft 规则:

    table inet firewalld {
        chain filter_IN_external_allow {
            udp dport 69 ct helper set "helper-tftp-udp"
        }
        chain filter_IN_internal_allow {
            udp dport 69 ct helper set "helper-tftp-udp"
            udp dport 69 ct state { new, untracked } accept
        }
    }
    

    这些规则永远不会匹配,因此是无用的:它们在输入路径中,而不是在正向路径中。

    使用正在运行的防火墙,这些(盲目复制的)规则添加在正确的位置:在转发路径中,将使 TFTP 工作:

    nft insert rule inet firewalld filter_FWDI_internal_allow udp dport 69 ct helper set "helper-tftp-udp"
    nft add rule inet firewalld filter_FWDI_internal_allow index 0 udp dport 69 ct state '{ new, untracked }' accept
    

    所以最后一个所谓的直接选项仍然是一个选项,所以一切都存储在firewalld的配置中。唉,文档有点误导:

    警告:直接规则行为因 FirewallBackend 的值而异。请参阅firewalld.direct(5)中的警告。

    不仔细阅读会认为通过接受nftables规则FirewallBackend=nftables会表现不同,但事实并非如此:

    # firewall-cmd --version
    0.8.0
    
    # firewall-cmd --direct --add-rule inet firewalld filter_FWDI_internal_allow 0 'udp dport 69 ct helper set "helper-tftp-udp" ct state new accept'
    Error: INVALID_IPV: invalid argument: inet (choose from 'ipv4', 'ipv6', 'eb')
    

    无需进行更多测试,此“功能”记录在那里:

    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):

    table ip handletftp
    delete table ip handletftp
    
    table ip handletftp {
        ct helper helper-tftp {
            type "tftp" protocol udp
        }
    
        chain sethelper {
            type filter hook forward priority 0; policy accept;
            ip saddr 192.168.1.0/24 ip daddr 10.0.10.10 udp dport 69 ct helper set "helper-tftp"
        }
    }
    

    由于表不同并且规则集永远不会被刷新,而是特定表被(原子地)删除并重新创建,这不会影响firewalld也不会影响它。

    优先级无关紧要:在firewalld的链之前或之后遍历该链不会改变数据包的命运(仍在firewalld手中)。无论顺序如何,如果数据包被firewalld接受,它也将激活此流的帮助程序。

    如果您选择使用nftables服务来加载此表,则必须对其进行编辑(例如:) systemctl edit --full nftables,因为除了加载一些可能不合适的默认规则外,它还会在停止或重新加载时刷新所有规则,从而中断firewalld。

    现在,TFTP 传输将起作用并激活特定的帮助程序,可以通过conntrack在传输期间运行两个命令来检查:

    # conntrack -E & conntrack -E expect
    [1] 3635
        [NEW] 300 proto=17 src=10.0.10.10 dst=10.0.10.11 sport=0 dport=56597 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.1.2 master-dst=10.0.10.10 sport=56597 dport=69 class=0 helper=tftp
        [NEW] udp      17 29 src=192.168.1.2 dst=10.0.10.10 sport=56597 dport=69 [UNREPLIED] src=10.0.10.10 dst=10.0.10.11 sport=69 dport=56597 helper=tftp
    [DESTROY] 299 proto=17 src=10.0.10.10 dst=10.0.10.11 sport=0 dport=56597 mask-src=255.255.255.255 mask-dst=255.255.255.255 sport=0 dport=65535 master-src=192.168.1.2 master-dst=10.0.10.10 sport=56597 dport=69 class=0 helper=tftp
        [NEW] udp      17 30 src=10.0.10.10 dst=10.0.10.11 sport=42032 dport=56597 [UNREPLIED] src=192.168.1.2 dst=10.0.10.10 sport=56597 dport=42032
     [UPDATE] udp      17 30 src=10.0.10.10 dst=10.0.10.11 sport=42032 dport=56597 src=192.168.1.2 dst=10.0.10.10 sport=56597 dport=42032
    

    上例中的第三个 NEW 条目实际上被标记为 RELATED(这是 tftp 助手的全部作用:期望某种类型的数据包将其视为相关),这将被防火墙接受。

    • 4

相关问题

  • nftable 规则在重新连接时失效(VDSL,ppp0)

  • 我的 nftables 规则阻止 IPv6

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve