本文介绍网络地址转换(Network address translation,简称为NAT)之Conntrack故障排除的内容。
连接跟踪和NAT 通过iptables或nftables配置的NAT建立在netfilters连接跟踪工具的顶部。这意味着,如果连接跟踪引擎出现任何问题,则NAT将不起作用。这可能会导致连接问题。无效的NAT规则会将内部地址泄漏到外部网络。使用nftables的“ct state”或iptables的“-m conntrack –ctstate”功能可以防止这种情况。如果数据包与INVALID状态匹配,则conntrack无法将数据包与已知连接关联。这也意味着NAT无法正常工作。 参考:介绍Linux系统下的conntrack命令:允许您检查和修改跟踪的连接。
连接跟踪的工作原理 连接跟踪器首先从数据包中提取IP地址和更高级别的协议信息。“高级协议信息”是传输协议的特定部分。一个常见的示例是源端口号和目标端口号(tcp,udp)或ICMP ID。一个更特殊的示例是PPTP呼叫ID。这些数据包字段(IP地址和协议特定信息)是用于检查连接跟踪表的查找关键字。 除了检查数据包是新的还是已知连接的一部分外,conntrack还执行特定于协议的测试。如果是UDP,它将检查数据包是否完整(接收到的数据包长度与UDP标头中指定的长度匹配),以及UDP校验和是否正确。对于其他协议,例如TCP,它还将检查: 1、TCP标志是否有效(例如,如果同时设置了RST和SYN标志,则将数据包视为无效)。 2、当数据包确认数据时,它将检查确认号是否与在另一个方向发送的数据匹配。 3、当数据包包含新数据时,它将检查此数据是否在对等方宣布的接收窗口内。 这些检查中的任何失败都会导致该数据包被视为无效。对于此类数据包,即使存在,conntrack既不会创建新的连接跟踪条目,也不会将其与现有条目关联。Conntrack可以配置为记录数据包被视为无效的原因。
记录内部conntrack信息 “net.netfilter.nf_conntrack_log_invalid”sysctl用于设置内核参数,以获取有关为何将数据包视为无效的更多信息。默认设置为0,将禁用此日志记录。正数(最多255个)指定将为该协议记录更多信息的信息。例如,6将为tcp打印更多信息,而17将为udp提供更多信息。这些数字与在/etc/protocols文件中找到的数字相同。特殊值255启用所有协议跟踪器的调试日志记录。 您可能需要设置特定的日志记录后端。使用“sysctl -a | grep nf_log”查看当前正在使用的日志后端。NONE表示未设置任何后端。输出示例: # sysctl -a | grep nf_log net.netfilter.nf_log.10 = NONE net.netfilter.nf_log.2 = NONE net.netfilter.nf_log_all_netns = 0 2是ipv4,3是arp,7用于网桥日志记录,10用于ipv6。对于连接跟踪,仅ipv4 (2)和ipv6 (10)是相关的。此处显示的最后一个sysctl – nf_log_all_netns –设置为默认值0,以防止其他名称空间充斥系统日志。可以将其设置为1来调试另一个网络名称空间中的问题。
Logger配置 此命令将打印可用日志模块的列表: # ls /lib/modules/$(uname -r)/kernel/net/netfilter/log /lib/modules/$(uname -r)/kernel/net/ip/netfilter/log* 命令: # modprobe nf_log_ipv4 加载ipv4日志模块。如果加载了多个日志模块,则可以使用sysctl设置首选/活动记录器。例如: # sudo sysctl net.netfilter.nf_log.2=nf_log_ipv4 告诉内核将ipv4数据包事件记录到syslog/journald。这只会影响conntrack调试生成的日志消息。由规则(例如“ipables -j NFLOG”)或LOG目标生成的日志消息不会更改,因为规则本身已经指定了要使用的日志类型(分别为nfnetlink和syslog/journald)。 此后,调试消息将出现在ulogd(如果通过nfnetlink配置)或系统日志(如果nf_log_ipv4是日志后端)中。
调试输出示例 使用“sudo sysctl net.netfilter.nf_log.2=nf_log_ipv4”和“sudo sysctl net.netfilter.nf_conntrack_log_invalid=6”创建的设置将出现以下示例: nf_ct_proto_6: invalid packet ignored in state ESTABLISHED SRC=10.47.217.34 DST=192.168.0.17 LEN=60 DF SPT=443 DPT=47832 SEQ=389276 ACK=3130 WINDOW=65160 ACK SYN 注:nf_ct_proto_6:ACK超出上限(尚未看到ACK数据)SRC=10.3.1.1 DST=192.168.0.1 LEN=60 DF SPT=443 DPT=49135 SEQ= ... 此转储包含数据包内容(例如,允许与流的tcpdump数据包捕获相关),以及将数据包标记为INVALID的原因。
动态调试 如果需要更多信息,则conntrack模块中有一些日志语句,可以在运行时使用动态调试基础结构启用该语句。 要检查此功能是否可用,请使用以下命令: # sudo grep nf_conntrack_proto_tcp /sys/kernel/debug/dynamic_debug/control 如果conntrack模块已加载并且动态调试功能可用,则输出类似于以下内容: net/netfilter/nf_conntrack_proto_tcp.c:1104 [nf_conntrack]nf_conntrack_tcp_packet =_ "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\012" net/netfilter/nf_conntrack_proto_tcp.c:1102 [nf_conntrack]nf_conntrack_tcp_packet =_ "tcp_conntracks: " net/netfilter/nf_conntrack_proto_tcp.c:1005 [nf_conntrack]nf_conntrack_tcp_packet =_ "nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\012" 注:net/netfilter/nf_conntrack_proto_tcp.c:999 [nf_conntrack]nf_conntrack_tcp_packet =_ "nf_ct_tcp: SYN代理客户端保持活动状态\012" 每行显示默认禁用的调试printk语句的位置。printk是Linux内核接口中的C函数,可将消息打印到内核日志中。首先是Linux内核源代码中的文件名,然后是行号。方括号包含该源文件所属的内核模块的名称。文件名和行号的组合允许启用或禁用这些printk语句。这个命令: # sudo echo "file net/netfilter/nf_conntrack_proto_tcp.c line 1005 +p" > /sys/kernel/debug/dynamic_debug/control 将启用net/netfilter/nf_conntrack_proto_tcp.c的第1005行中显示的printk语句。
使用“+p”替换为“-p”的同一命令将再次禁用此日志行。此功能不是连接跟踪所独有的:内核的许多部分都提供了此类调试消息。当出现问题并且需要有关conntrack内部状态的更多信息时,此技术很有用。
未确认和dying的清单 新分配的conntrack条目首先添加到未确认列表中。一旦所有iptables/nftables规则接受了数据包,conntrack条目就会从未确认列表移至主连接跟踪表。dying列表是相反的:从表中删除条目时,它将被放置在dying列表上。一旦所有引用该流的数据包都被丢弃,则释放该条目。这意味着conntrack条目始终在列表上:未确认列表,dying列表或conntrack哈希表列表。大多数条目将在哈希表中。 如果从表中删除是由于超时导致的,则不存在其他引用,并且该条目将立即释放。这就是UDP流通常会发生的情况。对于TCP,通常会由于特殊的TCP数据包(例如最后的TCP确认或TCP重置)而删除conntrack条目。这是因为TCP与UDP不同,它用信号通知状态转换,例如连接关闭。条目从表移到了dying列表。然后,在网络堆栈处理完“last packet”数据包后,将释放conntrack条目。 以下检查这些清单: # sudo conntrack -L unconfirmed # sudo conntrack -L dying 这两个命令显示列表。活动连接数(sudo conntrack -C)与连接跟踪表的内容(sudo conntrack -L)之间存在很大差异,表明存在问题。这些列表中任一个长时间保留的条目表示内核错误。预期的时间范围约为几微秒。
相关主题 |