2018年(21)
分类: LINUX
2018-09-19 15:49:19
经过上面一些辅助功能实现的分析,现在我们终于可以来分析conntrack的核心实现了。
conntrack 也是通过Netfilter的hook机制,在相应的点上拦截报文,进行相应的conntrack的建立和处理。
我们先来看看IPv4 Netfilter中各个模块的hook点分布。
下图的创意是我在网上的一篇博文里借鉴过来的(原文地址http://blog.chinaunix.net/uid-23069658-id-3162264.html)。
从上图我们可以看出各个模块注册的hook点及其他们的优先级。
1、因为conntrack是要分析报文的L4层信息,所有conntrack就无法处理ip分片报文的后续片报文。因此,如果打开了ip conntrack功能,conntrack模块就会在netfilter入口对ip分片报文进行重组,重组后再进行处理。
IP conntrack以最高优先级在Netfilter的入口处注册了hook函数,来进行IP分片报文的重组。
2、在Netfilter的入口点,conntrack会拦截报文,查找已建立的conntrack和报文进行关联,如果conntrack没有建立,就新建conntrack。
3、在Netfilter的出口点,conntrack拦截报文,对已经建立的conntrack的状态进行确认和更新。
net/ipv4/netfilter/nf_defrag_ipv4.c
static struct nf_hook_ops ipv4_defrag_ops[] = {
{
.hook = ipv4_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
},
{
.hook = ipv4_conntrack_defrag,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
},
};
对IPv4分片报文进行分片重组的代码我们这里就不进行分析了,大家知道conntrack会对所有进入Netfilter的IPv4分片报文进行重组即可。
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = {
//入口
{
.hook = ipv4_conntrack_in,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_CONNTRACK,
},
{
.hook = ipv4_conntrack_local,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_CONNTRACK,
},
//出口
{
.hook = ipv4_confirm,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
{
.hook = ipv4_confirm,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
},
};
我们看一看Netfilter中入口对报文的处理:
static unsigned int ipv4_conntrack_in(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return nf_conntrack_in(dev_net(in), PF_INET, hooknum, skb);
}
static unsigned int ipv4_conntrack_local(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr))
return NF_ACCEPT;
return nf_conntrack_in(dev_net(out), PF_INET, hooknum, skb);
}
两个函数最后到调用了nf_conntrack_in来处理报文。
Netfilter中出口对报文的处理都是调用了ipv4_confirm来处理报文。
(未完待续)