网络地址转换第 1 部分 – 数据包跟踪

[ad_1]

关于网络地址转换 (NAT) 的系列文章的第一篇。 第 1 部分展示了如何使用 iptables/nftables 数据包跟踪功能来查找与 NAT 相关的连接问题的根源。

介绍

网络地址转换是将容器或虚拟机暴露给更广泛的互联网的一种方式。 传入的连接请求将其目标地址重写为不同的地址。 然后将数据包路由到容器或虚拟机。 相同的技术可用于负载平衡,其中传入连接分布在机器池中。

当网络地址转换未按预期工作时,连接请求失败。 错误的服务被暴露,连接在错误的容器中结束,请求超时,等等。 调试此类问题的一种方法是检查传入请求是否与预期或配置的转换相匹配。

连接跟踪

NAT 不仅仅涉及更改 IP 地址或端口号。 例如,将地址X映射到Y时,不需要添加规则来进行反向转换。 一个名为“conntrack”的网络过滤器系统识别对现有连接的回复的数据包。 每个连接都有自己的 NAT 状态附加到它。 反向翻译是自动完成的。

规则集评估跟踪

实用程序 nftables(以及在较小程度上,iptables)允许检查数据包的评估方式以及规则集中的哪些规则与其匹配。 为了使用这个特殊功能,在合适的位置插入“跟踪规则”。 这些规则选择应跟踪的数据包。 让我们假设来自 IP 地址 C 的主机试图访问地址 S 和端口 P 上的服务。我们想知道选择了哪个 NAT 转换,检查了哪些规则以及数据包是否在某处被丢弃。

因为我们正在处理传入的连接,所以在 prerouting 挂钩点添加规则。 预路由意味着内核尚未决定将数据包发送到哪里。 目标地址的更改通常会导致数据包被转发而不是由主机本身处理。

最初设定

# nft 'add table inet trace_debug'
# nft 'add chain inet trace_debug trace_pre { type filter hook prerouting priority -200000; }'
# nft "insert rule inet trace_debug trace_pre ip saddr $C ip daddr $S tcp dport $P tcp flags syn limit rate 1/second meta nftrace set 1"

第一条规则添加了一个新表,这允许以后更容易地删除跟踪和调试规则。 单个“nft delete table inet trace_debug”就足以撤消在调试期间添加到临时表的所有规则和链。

第二条规则在做出路由决定(预路由)之前创建一个基本钩子,并具有负优先级值,以确保在连接跟踪和 NAT 规则之前对其进行评估。

然而,唯一重要的部分是第三条规则的最后一个片段:“meta nftrace set 1”。 这将为所有匹配规则的数据包启用跟踪事件。 尽可能具体以获得良好的信噪比。 考虑添加速率限制以将跟踪事件的数量保持在可管理的级别。 每秒或每分钟限制一个数据包是一个不错的选择。 提供的示例跟踪所有来自主机 $C 并前往目标主机 $S 上的目标端口 $P 的 syn 和 syn/ack 数据包。 限制子句防止事件泛滥。 在大多数情况下,跟踪单个数据包就足够了。

该过程与 iptables 用户类似。 等效的跟踪规则如下所示:

# iptables -t raw -I PREROUTING -s $C -d $S -p tcp --tcp-flags SYN SYN  --dport $P  -m limit --limit 1/s -j TRACE

获取跟踪事件

本机 nft 工具的用户可以只运行 nft 跟踪模式:

# nft monitor trace

这会打印出接收到的数据包和所有匹配数据包的规则(使用 CTRL-C 停止它):

trace id f0f627 ip raw prerouting  packet: iif "veth0" ether saddr ..

我们将在下一节中更详细地研究这一点。 如果你使用 iptables,首先通过“iptables –version”命令检查安装的版本。 例子:

# iptables --version
iptables v1.8.5 (legacy)

(legacy) 意味着跟踪事件被记录到内核环形缓冲区。 您需要检查 dmesg 或 journalctl。 调试输出缺少一些信息,但在概念上与新工具提供的信息相似。 您需要检查记录的规则行号并将其与活动的 iptables 规则集相关联。 如果输出显示 (nf_tables),则可以使用 xtables-monitor 工具:

# xtables-monitor --trace

如果该命令只显示版本,您还需要查看 dmesg/journalctl。 xtables-monitor 使用与 nft 监视器跟踪工具相同的内核接口。 它们唯一的区别是它将以 iptables 语法打印事件,并且如果您混合使用 iptables-nft 和 nft,它将无法打印使用地图/集和其他 nftables-only 功能的规则。

例子

假设您想调试一个非工作端口转发到虚拟机或容器。 命令“ssh -p 1222 10.1.2.3”应该提供对在具有该地址的机器上运行的容器的远程访问,但连接尝试超时。

您可以访问运行容器映像的主机。 登录并添加跟踪规则。 请参阅前面有关如何添加临时调试表的示例。 跟踪规则如下所示:

nft "insert rule inet trace_debug trace_pre ip daddr 10.1.2.3 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1"

添加规则后,以跟踪模式启动 nft:nft monitor trace,然后重试失败的 ssh 命令。 如果规则集很大,这将产生大量输出。 不要担心下面的大型示例输出——下一节将逐行进行演练。

trace id 9c01f8 inet trace_debug trace_pre packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syn
trace id 9c01f8 inet trace_debug trace_pre rule ip daddr 10.2.1.2 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1 (verdict continue)
trace id 9c01f8 inet trace_debug trace_pre verdict continue
trace id 9c01f8 inet trace_debug trace_pre policy accept
trace id 9c01f8 inet nat prerouting packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp  tcp dport 1222 tcp flags == syn
trace id 9c01f8 inet nat prerouting rule ip daddr 10.1.2.3  tcp dport 1222 dnat ip to 192.168.70.10:22 (verdict accept)
trace id 9c01f8 inet filter forward packet: iif "enp0" oif "veth21" ether saddr .. ip daddr 192.168.70.10 .. tcp dport 22 tcp flags == syn tcp window 29200
trace id 9c01f8 inet filter forward rule ct status dnat jump allowed_dnats (verdict jump allowed_dnats)
trace id 9c01f8 inet filter allowed_dnats rule drop (verdict drop)
trace id 20a4ef inet trace_debug trace_pre packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syn

逐行跟踪演练

生成的第一行是触发后续跟踪输出的数据包 ID。 尽管这与 nft 规则语法的语法相同,但它包含刚刚接收到的数据包的标头字段。 您将找到接收网络接口的名称(此处命名为“enp0”)、数据包的源和目标 mac 地址、源 ip 地址(可能很重要 – 也许报告者从错误/意外的主机连接)和tcp 源端口和目标端口。 您还会在开头看到一个“跟踪 ID”。 此标识告诉哪个传入数据包与规则匹配。 第二行包含数据包匹配的第一条规则:

trace id 9c01f8 inet trace_debug trace_pre rule ip daddr 10.2.1.2 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1 (verdict continue)

这是刚刚添加的跟踪规则。 第一条规则始终是激活数据包跟踪的规则。 如果在此之前还有其他规则,我们将不会看到它们。 如果根本没有跟踪输出,则跟踪​​规则本身永远不会达到或不匹配。 接下来的两行表明没有进一步的规则,并且“trace_pre”钩子允许数据包继续(判断接受)。

下一个匹配规则是

trace id 9c01f8 inet nat prerouting rule ip daddr 10.1.2.3  tcp dport 1222 dnat ip to 192.168.70.10:22 (verdict accept)

此规则设置到不同地址和端口的映射。 如果 192.168.70.10 确实是所需虚拟机的地址,则到目前为止没有问题。 如果它不是正确的 VM 地址,则该地址要么输入错误,要么匹配了错误的 NAT 规则。

IP转发

接下来我们可以看到 IP 路由引擎告诉 IP 栈需要将数据包转发到另一台主机:

trace id 9c01f8 inet filter forward packet: iif "enp0" oif "veth21" ether saddr .. ip daddr 192.168.70.10 .. tcp dport 22 tcp flags == syn tcp window 29200

这是收到的数据包的另一个转储,但有一些有趣的变化。 现在有一个输出接口集。 这在以前不存在,因为以前的规则位于路由决策(预路由挂钩)之前。 id 和之前一样,所以这还是同一个数据包,但是地址和端口已经改变了。 如果有匹配“tcp dport 1222”的规则,它们将不再对这个数据包产生影响。

如果线路不包含输出接口 (oif),则路由决策将数据包引导至本地主机。 路由调试是一个不同的主题,这里不做介绍。

trace id 9c01f8 inet filter forward rule ct status dnat jump allowed_dnats(判决跳转 allowed_dnats)

这表明数据包匹配跳转到名为“allowed_dnats”的链的规则。 下一行显示了连接失败的来源:

trace id 9c01f8 inet filter allowed_dnats rule drop (verdict drop)

该规则无条件地丢弃数据包,因此不存在数据包的进一步日志输出。 下一行是不同数据包的结果:

跟踪 ID 20a4ef inet trace_debug trace_pre 数据包:iif “enp0” ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syn

trace id 不同,但是数据包具有相同的内容。 这是一次重传尝试:第一个数据包被丢弃,因此 TCP 重试。 忽略剩余的输出,它不包含新信息。 是时候检查那条链了。

规则集调查

上一节发现数据包被丢弃在 inet 过滤器表中名为“allowed_dnats”的链中。 是时候看看了:

# nft list chain inet filter allowed_dnats
table inet filter {
 chain allowed_dnats {
  meta nfproto ipv4 ip daddr . tcp dport @allow_in accept
  drop
   }
}

接受@allow_in 集合中的数据包的规则没有出现在跟踪日志中。 通过列出元素来仔细检查地址是否在 @allow_set 中:

# nft "get element inet filter allow_in { 192.168.70.10 . 22 }"
Error: Could not process rule: No such file or directory

正如预期的那样,地址-服务对不在集合中。 我们现在添加它。

# nft "add element inet filter allow_in { 192.168.70.10 . 22 }"

现在运行查询命令,它将返回新添加的元素。

# nft "get element inet filter allow_in { 192.168.70.10 . 22 }"
table inet filter {
   set allow_in {
      type ipv4_addr . inet_service
      elements = { 192.168.70.10 . 22 }
   }
}

ssh 命令现在应该可以工作并且跟踪输出反映了更改:

跟踪 ID 497abf58 inet 过滤器转发规则 ct 状态 dnat 跳转 allowed_dnats(判决跳转 allowed_dnats)

跟踪 ID 497abf58 inet 过滤器 allowed_dnats 规则元 nfproto ipv4 ip daddr。 tcp dport @allow_in 接受(判决接受)

跟踪 ID 497abf58 ip postrouting 数据包:iif “enp0” oif “veth21” ether .. trace id 497abf58 ip postrouting 策略接受

这表明数据包通过了转发路径中的最后一个钩子 – 路由后。

如果连接仍然无法正常工作,则问题出在数据包管道后面和 nftables 规则集之外的某个地方。

概括

本文介绍了如何使用 nftables 跟踪机制检查数据包丢失和其他连接问题来源。 本系列后面的一篇文章展示了如何检查连接跟踪子系统和可能附加到被跟踪流的 NAT 信息。

[ad_2]

Related Posts