iptables nat的实现根基:conntrack
conntrack
conntrack 是 Linux 下的一个内核模块,这个名字是 connection track 的缩写, 顾名思义,这个模块就是用来做连接跟踪的。 然而这里的链接需要同 TCP 协议中的连接区分开来, 它指的是通信的两个端点之间用于传输数据的连接, 因此它不止可以用来跟踪 TCP 的连接,还可以跟踪 UDP、ICMP 协议保报文这样”连接“。 conntrack实现跟踪的原理是conntrack 维护一张连接表(conntrack table)。
先提netfilter框架
netfilter是linux内核中的一个数据包处理框架,用于替代原有的ipfwadm和ipchains等数据包处理程序。netfilter的功能包括数据包过滤,修改,SNAT/DNAT等。netfilter在内核协议栈的不同位置实现了5个hook点,其它内核模块(比如ip_tables)可以向这些hook点注册处理函数,这样当数据包经过这些hook点时,其上注册的处理函数就被依次调用,用户层工具像iptables一般都需要相应内核模块ip_tables配合以完成与netfilter的交互。netfilter hooks、ip{6}_tables、connection tracking、和NAT子系统一起构成了netfilter框架的主要部分。
详情见:netfilter框架解析
netfilter转发链路
--->PRE------>[ROUTE]--->FWD---------->POST------>
Conntrack | Mangle ^ Mangle
Mangle | Filter | NAT (Src)
NAT (Dst) | | Conntrack
(QDisc) | [ROUTE]
v |
IN Filter OUT Conntrack
| Conntrack ^ Mangle
| Mangle | NAT (Dst)
v | Filter
netfilter全链路图
conntrack在流量转发中有着比nat更高的优先级
/* hook函数默认优先级设置,数值越小优先级越高 */
enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN, /* 最高优先级 */
NF_IP_PRI_RAW_BEFORE_DEFRAG = -450, /* 涉及IP分片重组的RAW */
NF_IP_PRI_CONNTRACK_DEFRAG = -400, /* 涉及IP分片重组的连接跟踪 */
NF_IP_PRI_RAW = -300, /* RAW表,用于取消连接跟踪 */
NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200, /* 连接跟踪开始 */
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100, /* NAT的改变目的地址, DNAT or de-SNAT */
NF_IP_PRI_FILTER = 0, /* IPTABLES的数据包过滤 */
NF_IP_PRI_SECURITY = 50,
NF_IP_PRI_NAT_SRC = 100, /* NAT的改变源地址, SNAT or de-DNAT */
NF_IP_PRI_SELINUX_LAST = 225,
NF_IP_PRI_CONNTRACK_HELPER = 300,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, /* 连接确认 */
NF_IP_PRI_LAST = INT_MAX, /* 最低优先级 */
};
优先级CONNTRACK > DNAT > FILTER > SNAT > CONNTRACK_CONFIRM
分析:
我们知道NAT是在连接跟踪的基础上实现的,所以连接跟踪肯定是在NAT之前建立的。从这里注册的钩子函数的优先级可以看到,NAT的优先级是NF_IP_PRI_NAT_SRC = -100而连接跟踪的优先级是NF_IP_PRI_CONNTRACK = -200,在Netfilter框架中优先级数值越小,优先级越高,越先被调用。所以可以看到NAT是在连接跟踪建立之后进行的。
融入了conntrack的iptables四表五链
conntrack虽然不属于iptables四表五链,但他维护的连接状态可以被四表五链使用,且四表五链在做NAT的时候,是依赖于conntrack的
conntrack table
conntrack 维护一张连接表——conntrack table。 通过 netfilter 的 hook 机制,conntrack 模块可以检查系统中进出的每个网络数据包。 当发现一条新的连接建立时,比如检查到一个 TCP SYNC 数据包, conntrack 就在 conntrack table 中添加一条连接记录。 可以用 Linux 中的 conntrack 指令查看 conntrack table, conntrack table 表项中记录的格式如下:
example:
tcp 6 48 SYN_SENT src=192.168.199.132 dst=172.217.24.14 sport=58074 dport=443 [UNREPLIED] src=172.217.24.14 dst=192.168.199.132 sport=443 dport=58074 mark=0 use=1
conntrack中的连接不等于tcp中的连接
Netfilter 中每个 flow 都称为一个 connection,即使是对那些非面向连接的协议(例 如 UDP)
conntrack工作原理
conntrack 是一个非常重要的模块,它是 ipvs 负载均衡、NAT 的核心依赖模块。 以 SNAT 为例我们来说明 conntrack 的一个应用场景。 当 NAT 模块收到一个新的报文时,它先查看 conntrack table, 如果其中存在相关连接信息的表项,它会根据这个表项修改报文的 ip 和 端口信息。 当相关表项不存在时,遍历iptabls NAT表规则判断是否需要对报文做地址转换, 如果符合 NAT 地址转换规则,那么 NAT 会在 conntrack talbe 中写入转换后的地址, 后续地址转换直接查 conntrack table 即可完成。
Linux 的连接跟踪是在 Netfilter 中实现的
Tuple 是连接跟踪中最重要的概念之一:
一个 tuple 定义一个单向(unidirectional)flow。
Netfilter 中的连接跟踪点
进入 NAT
工作原理:
首先查询 conntrack 记录,如果不存在,就意味着无法跟踪这个连接,那就更不可能做 NAT 了,因此直接返回。如果找到了 conntrack 记录,并且是 IP_CT_RELATED、IP_CT_RELATED_REPLY 或 IP_CT_NEW 状态,就去获取 NAT 规则。如果没有规则,直接返回 NF_ACCEPT,对包不 做任何改动;如果有规则,最后执行 nf_nat_packet,这个函数会进一步调用 manip_pkt 完成对包的修改,如果失败,包将被丢弃。
conntrack监控
conntrack常见问题:连接太多导致 conntrack table 被打爆