💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、豆包、星火、月之暗面及文生图、文生视频 广告
[TOC] 数据包sk_buff结构体中有一个字段`nfctinfo`,用来表示这个数据包的状态,它的取值可以参考结构体[enum ip_conntrack_info](https://www.kancloud.cn/pshizhsysu/network/2158321#enum__ip_conntrack_info_140)。连接nf_conn结构体中有一个字段`unsigned status`,用来表示这个连接的状态,它是一个位图,可以参考结构体[enum ip_conntrack_status](https://www.kancloud.cn/pshizhsysu/network/2158321#enum_ip_conntrack_status_169)。接下来我们来介绍一下两个字段是如何变化的。 ## **sk_buff -> nfctinfo** #### **第一个请求包** 当第一个请求包到达NF_INET_PRE_ROUTING处时,进入`nf_conntrack_in()`函数,该函数会调用`resolve_normal_ct()`函数,我们来看一下这个函数对nfctinfo的处理逻辑,如下: 结论就是,第一个请求包经过PREROUTING后,它的nfctinfo会被设置为`IP_CT_NEW` ``` static inline struct nf_conn * resolve_normal_ct(...) { ... /* It exists; we have (non-exclusive) reference. */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { *ctinfo = IP_CT_ESTABLISHED_REPLY; /* Please set reply bit if this packet OK */ *set_reply = 1; } else { /* Once we've had two way comms, always ESTABLISHED. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { pr_debug("nf_conntrack_in: normal packet for %p\n", ct); *ctinfo = IP_CT_ESTABLISHED; } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { pr_debug("nf_conntrack_in: related packet for %p\n", ct); *ctinfo = IP_CT_RELATED; } else { // 第一个请求包,会走到这里 pr_debug("nf_conntrack_in: new packet for %p\n", ct); *ctinfo = IP_CT_NEW; } *set_reply = 0; } ... skb->nfctinfo = *ctinfo; // 然后在这里设置数据包的nfctinfo为IP_CT_NEW ... } ``` 当第一个请求包到达NF_INET_POST_ROUTING处时,进入`nf_conntrack_confirm()`函数,该函数会调用`__nf_conntrack_confirm()`函数,但是我们发现在整个函数的执行与调用过程中,并没有看到对nfctinfo的更改。也说就是,数据包的nfctinfo在出口处并不会发生改变。所以,在POSTROUTING处,第一个请求包的nfctinfo也就`IP_CT_NEW`。 #### **第一个回复包** 根据上面的分析我们知道在连接跟踪的出口处是不会改变数据包的nfctinfo的,所以我们只看连接跟踪的入口片。 我们还是来看`resolve_normal_ct()`这个函数,逻辑如下:对于回复包,不管是第一个还是第N个,nfctinfo都会被设置为`IP_CT_ESTABLISHED_REPLY` ``` static inline struct nf_conn * resolve_normal_ct(...) { ... /* It exists; we have (non-exclusive) reference. */ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { // 回复包会进入这个逻辑 *ctinfo = IP_CT_ESTABLISHED_REPLY; /* Please set reply bit if this packet OK */ *set_reply = 1; } else { ... } ... skb->nfctinfo = *ctinfo; // 然后在这里设置数据包的nfctinfo ... } ``` #### **第N个请求包** 对于第N(N>=2)个请求包,它的逻辑如下:也就是说,第N个请求包,它的nfctinfo为`IP_CT_ESTABLISHED` ``` static inline struct nf_conn * resolve_normal_ct(...) { ... if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) { ... } else { /* Once we've had two way comms, always ESTABLISHED. */ if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { // 第N个请求包会走到这里(N>=2) pr_debug("nf_conntrack_in: normal packet for %p\n", ct); *ctinfo = IP_CT_ESTABLISHED; } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) { pr_debug("nf_conntrack_in: related packet for %p\n", ct); *ctinfo = IP_CT_RELATED; } else { pr_debug("nf_conntrack_in: new packet for %p\n", ct); *ctinfo = IP_CT_NEW; } *set_reply = 0; } ... skb->nfctinfo = *ctinfo; // 然后在这里设置数据包的nfctinfo ... } ``` #### **第N个回复包** 在上面的“第一个回复包”处我们知道,回复包不管是第几个,它的nfctinfo都是`IP_CT_ESTABLISHED_REPLY` ## **nf_conn -> status** to be continued