云网牛站
所在位置:首页 > Linux云服务器 > 用iptables/nftables跟踪机制检查数据包丢失和其他连接问题来源

用iptables/nftables跟踪机制检查数据包丢失和其他连接问题来源

2021-01-06 11:25:28作者:优原稿源:云网牛站

本文介绍如何使用iptables/nftables数据包跟踪功能来查找与NAT相关的连接问题的根源,即用iptables/nftables跟踪机制检查数据包丢失和其他连接问题来源,以下是具体实施的方法。

用iptables/nftables跟踪机制检查数据包丢失和其他连接问题来源

 

介绍

1、网络地址转换

网络地址转换是将容器或虚拟机暴露于更广泛的Internet的一种方法。传入的连接请求会将其目标地址重写为另一个。然后,将数据包路由到容器或虚拟机。可以使用相同的技术进行负载平衡,在该负载平衡中,传入的连接将分布在一组计算机中。

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

2、连接跟踪

NAT不仅仅涉及更改IP地址或端口号。例如,将地址X映射到Y时,无需添加规则来执行反向转换。一个称为“conntrack”的netfilter系统可以识别对现有连接的答复的数据包。每个连接都具有自己的NAT状态。逆向翻译是自动完成的。

3、规则集评估跟踪

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

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

参考:iptables命令_Linux iptables命令使用详解:Linux下常用的防火墙软件

 

初始设置

# 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数据包。limit子句可防止事件泛滥。在大多数情况下,仅跟踪一个数据包就足够了。

对于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)

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

# xtables-monitor --trace

如果命令仅显示版本,则还需要查看dmesg/journalctl。xtables-monitor使用与nft Monitor跟踪工具相同的内核接口。它们的唯一区别在于,它将以iptables语法打印事件,并且,如果同时使用iptables-nft和nft,则它将无法打印使用映射/设置和其他仅适用于nftables的功能的规则。

 

例子

假设您想调试转发至虚拟机或容器的非工作端口。命令“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源和目标端口。您还将在开始时看到“trace 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的地址,到目前为止没有问题。如果其不是正确的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 (verdict jump allowed_dnats)

这表明数据包与跳到名为“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不同,但是数据包具有相同的内容。这是一次重传尝试,第一个数据包被丢弃,因此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 }"

现在运行query命令,它将返回新添加的元素:

# 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命令现在应该可以运行,并且跟踪输出反映了更改:

trace id 497abf58 inet filter forward rule ct status dnat jump allowed_dnats (verdict jump allowed_dnats)

trace id 497abf58 inet filter allowed_dnats rule meta nfproto ipv4 ip daddr . tcp dport @allow_in accept (verdict accept)

trace id 497abf58 ip postrouting packet: iif "enp0" oif "veth21" ether .. trace id 497abf58 ip postrouting policy accept

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

如果连接仍然无法正常工作,则问题可能出在稍后的数据包管道中以及nftables规则集之外。

 

相关主题

Linux系统管理员要知道的16个iptables使用技巧

精选文章
热门文章