[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
- 应用层
- HTTP
- Cookie
- Session
- HTTP报文格式
- HTTP的Header字段
- HTTPS
- 简介
- 原理
- RSA加密与解密
- 证书签名与验证
- TLS双向认证
- openssl命令汇总
- DNS
- DNS的记录类型
- DNS的报文格式
- FAQ
- 传输层
- TCP
- CloseWait
- 网络层
- IPv6
- 链路层
- 链接层基础知识
- VLAN
- FAQ
- Linux网络收发包
- 网卡收包
- 网卡发包
- 收发包FAQ
- LVS
- 安装-DR模式
- 基本原理
- Ipvsadm命令
- Netfilter
- Netfilter简介
- 注册钩子函数
- Netfilter中数据包流向
- Iptables的数据结构
- 连接跟踪
- 初识连接跟踪
- 连接跟踪详解
- 连接跟踪数据结构
- 数据包与连接的状态
- NAT
- IPVS
- KubeProxy的IPVS模式
- Linux虚拟网络设备
- 虚拟网络设备简介
- Tap
- VethPair
- Vlan
- Vxlan
- Flannel的VXLAN原理
- Openstack的VXLAN原理
- VXLAN总结
- Bridge
- 给容器设置主机网段IP
- Macvlan
- Ipvlan
- IPIP
- IPIP使用介绍
- IPIP源码分析
- Limdiag网络
- 详细设计
- kubeovn
- IP命令
- Calico
- Calico常见问题
- ARP无响应
- 其他
