# nf\_conntrack连接跟踪机制

## 1、前言

前段时间接手的一个连接跟踪表满导致网络不通的问题。

&#x20;  **问题介绍：**

* 网络不通，ping，ssh均失败。
* 查看dmesg日志有报错：kernel: nf\_conntrack: nf\_conntrack: table full, dropping packet &#x20;
* sysctl net.netfilter.nf\_conntrack\_count达到了net.netfilter.nf\_conntrack\_max的值
* 但查看  cat /proc/net/nf\_conntrack | wc -l    只有200多。

&#x20;   **主要问题：nf\_conntrack\_count计数与/proc/net/nf\_conntrack下的记录数不一致**

为进一步调查这个问题，对linux系统的连接跟踪模块进行了学习。本文梳理一下目前对nf\_conntrack模块的一些个人理解。

## 2、连接跟踪机制

* ### **背景知识：netfilter（这部分主要参考其他介绍资料）**

&#x20;      Netfilter是一个内核架构，是集成到linux内核协议栈的一套防火墙系统，可通过用户空间（iptables等）的工具来把相关配置下发给Netfilter。

&#x20;      **Netfilter相关背景：五链、四表、hook点、hook函数**

&#x20;      **五链**：**内核在网络上定义的五个关键位置**，进路由(PREROUTING)、进系统(INPUT) 、转发(FORWARD)、出系统(OUTPUT)、出路由(POSTROUTING)。

![](https://img-blog.csdnimg.cn/20200506213444537.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

&#x20;      **PREROUTING链:**&#x5728;对数据包作路由选择之前，应用此链中的规则。

&#x20;      **INPUT链：**&#x5904;理入站数据包，当接收到访问防火墙本机地址的数据包(入站)时，应用此链中的规则。

&#x20;      **OUTPUT链：**&#x5904;理出站数据包，当防火墙本机向外发送数据包(出站)时，应用此链中的规则。

&#x20;      **FORWARD链：**&#x5904;理转发数据包.当接收到需要通过防火墙发送给其他地址的数据包(转发)时，应用此链中的规则。

&#x20;      **POSTROUTING链:**&#x5728;对数据包作路由选择之后，应用此链中的规则。

&#x20;      **四表：即每个链中存储的规则。**&#x6570;据包到了上述的“链”处时，就会去对应“表”中查询设置的规则，然后决定是否放行、丢弃、转发还是修改等等操作。具体的四表为：

| **表名（优先级从上到下）** | **功能**                       |
| --------------- | ---------------------------- |
| Raw 表           | 决定数据包是否被状态跟踪机制处理             |
| Mangle表         | 修改数据包的服务类型、TTL、并且可以配置路由实现QOS |
| Nat表            | 用于网络地址转换（IP、端口）              |
| Filter表         | 过滤数据包                        |

表和链的对应关系：

![](https://img-blog.csdnimg.cn/20200506213817541.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

&#x20;      **Hook点：五链对应的位置我们又称之为hook点。**&#x6BCF;个hook点上针对不同的协议、不同的hook函数优先级，分配了一系列hook函数。数据包每到一个hook点，各协议会**按照hook函数优先级从小到大的顺序执行hook函数**。

&#x20;      **Hook函数：在hook点上设置的数据包处理函数。**

&#x20;      关于**netfilter中协议类型，hook点，hook函数，优先级的关系**，下图可以直观体现：

&#x20;      ![](https://img-blog.csdnimg.cn/20200506213943451.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

&#x20;      下图对更加详细的列出了各个阶段的hook函数

&#x20;      ![](https://img-blog.csdnimg.cn/20200506214026328.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

* ### **nf\_conntrack连接追踪模块**

&#x20;      nf\_conntrack模块维护着系统的一个链接追踪表。内部用1个哈希表记录已建立的连接，包括其他机器到本机、本机到其他机器、本机到本机（例如 ping 127.0.0.1 也会被跟踪）。如果连接进来比释放的快，把哈希表塞满了，新连接的数据包会被丢掉，同时dmesg日志会打印kernel: nf\_conntrack: nf\_conntrack: table full, dropping packet信息，外部表现为网络不通。

&#x20;        **nf\_conntrack\_count模块内部维护者四张表：**

1. **Confirm表**：系统正式连接追踪表，即/proc/net/nf\_conntrack看到的列表
2. **Expired表**：期望值表（暂没有深入了解）
3. **Unconfirm表**：记录已经进入连接追踪系统，但还没有加入正式追踪表的连接
4. **Dying表**：记录已经在正式追踪表超时删除，等待系统最终删除的连接块

&#x20;       net.netfilter.nf\_conntrack\_count统计的是上述所有表中连接的数量，而/proc/net/nf\_conntrack看到的信息只有confirm表的信息。**所以就要确认其他连接是存在哪张表里面了。首先要先理解连接加入confirm表和从confirm表删除的机制**

* **连接加入到nf\_conntrack模块流程**

&#x20;      其中conntrack对数据包进行追踪的hook函数即上图中的红框（输入连接）、蓝框（输出连接）所对应的函数。下面分析输入连接的跟踪ipv4\_conntrack\_in和ipv4\_confirm函数（输出过程的跟踪连接机制同理）：

**当数据包经过了PRE\_ROUNTING hook点：**

![](https://img-blog.csdnimg.cn/20200506214238908.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

**当数据包经过INPUT hook点：**

![](https://img-blog.csdnimg.cn/20200506214322205.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

* **连接删除出nf\_connntrack模块流程**

&#x20;      通过初步代码分析，确认系统是通过nf\_ct\_delete函数进行的连接删除工作，后续利用dump\_stack函数，打印出调用栈，其删除实际是通过工作队列进行处理的，具体流程如下

**当系统调度到worker\_thread**

![](https://img-blog.csdnimg.cn/20200506214419368.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2MzgyMDYy,size_16,color_FFFFFF,t_70)

## 3、连接跟踪机制可能出的问题

&#x20;       通过2部分介绍发现：在连接加入系统confirm表以及连接从系统中删除的流程中，均有可能出现nf\_conntrack堆积造成问题。

&#x20;       **从连接加入角度分析：**&#x8FDE;接跟踪块在PRE\_ROUNTING hook点执行完nf\_ct\_add\_to\_unconfirmed\_list后，会加入unconfirm列表，而此时nf\_conntrack\_count值已然增加；那么此时有两种情况造成其不能加入confirm列表：

1. &#x20;**走到INPUT hook点之前被NF\_DROP或者NF\_STOLEN跳过之后的hook函数流程**
2. &#x20;**执行ipv4\_confirm流程没有走完（这个概率较小）。**

&#x20;      对于1中提到的情况，通过本地构造测试，返回NF\_DROP会直接丢弃该包，nf\_conntrack\_count也会对应清除；返回NF\_STOLEN则会使数据包一直在unconfirm列表中，nf\_conntrack\_count不减少。同时网上也找到了因错误返回NF\_STOLEN造成nf\_conntrack\_count堆积的案例：<https://www.spinics.net/lists/netfilter-devel/msg11924.html>

&#x20;      该问题通过修改NF\_STOLEN处理机制，即同步到NF\_DROP来解决，但新版本内核并没有合入该改动。

&#x20;     **从连接删除角度分析：**&#x53EF;以看出当confirm列表中的连接块超时之后，会通过工作队列进行删除工作。其中会先将链接从confirm列表删除，加入dying列表，此时有两种情况会出现nf\_conntrack\_count计数与confirm列表不同步的问题：

1. **连接块的连接引用计数不为1**
2. &#x20;**连接快引用计数为空**

&#x20;      **通过上述代码分析，可以发现连接块在“加入confirm表”以及“从confirm列表删除”的过程中，均有可能出现nf\_conntrack\_count计数与confirm列表不对应的现象。具体要在问题环境通过conntack工具查看，这个工具的使用和操作技巧，下一篇再具体介绍。**

**参考资料：**

<https://blog.csdn.net/wuruixn/article/details/7957368>

<https://www.cnblogs.com/codestack/p/10850669.html>

<https://blog.csdn.net/jasonchen_gbd/article/details/44873089>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://xn--7dvp7de53ainp.gitbook.io/untitled/gong-zuo-bi-ji/an-quan/openssl/nfconntrack-lian-jie-gen-zong-ji-zhi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
