背景
最近在学习了解内核中关于连接跟踪的相关处理,众所周知,内核中连接跟踪处理依附于Netfilter内核架构,通过在内核协议栈报文处理过程中不同的HOOK点(钩子)设置HOOK处理函数,实现连接跟踪相关处理,相关定义如下:
static const struct nf_hook_ops ipv4_conntrack_ops[] = {
{
.hook = ipv4_conntrack_in,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = ipv4_conntrack_local,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = nf_confirm,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
{
.hook = nf_confirm,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
};
之前基于接收报文简单介绍了连接建立(ipv4_conntrack_in)与连接确认(nf_confirm)的处理过程,关于本机外出报文连接相关处理还不清楚,这里进一步学习完善。
本机外出报文
从上述hook操作的相关定义可知,本机外出报文的连接处理对应HOOK点NF_INET_LOCAL_OUT,处理函数为ipv4_conntrack_local();
首先确认下调用位置,__ip_local_out()函数是本机外出报文(L3报文)的必经之路,在函数__ip_local_out()内部存在如下代码:
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
net, sk, skb, NULL, skb_dst(skb)->dev, dst_output);
接下来我们重点分析下 ipv4_conntrack_local()函数处理逻辑 。
ipv4_conntrack_local函数
函数具体处理逻辑如下:
static unsigned int ipv4_conntrack_local(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
/* 分片报文处理,从这里看如果分片报文走到这里要么已建立连接,要么不建连接直接返回 */
if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
enum ip_conntrack_info ctinfo;
struct nf_conn *tmpl;
tmpl = nf_ct_get(skb, &ctinfo);
if (tmpl && nf_ct_is_template(tmpl)) {
/* when skipping ct, clear templates to avoid fooling
* later targets/matches
*/
skb->_nfct = 0;
nf_ct_put(tmpl);
}
return NF_ACCEPT;
}
/* 建立连接的核心处理函数 */
return nf_conntrack_in(skb, state);
}
从上述代码可以看出ipv4_conntrack_local函数的核心处理为调用nf_conntrack_in()函数,和外来报文建立连接的后续处理逻辑一致,具体可参考之前的博客:nf_conntrack(一)-连接建立;
由此可见,本机外出报文、外来报文建立连接的处理过程是相似的,只是报文处理的位置有所不同。