如笔记连接跟踪子系统之AF_INET初始化所述,为了支持连接跟踪子系统,AF_INET协议族在4个HOOK点共注册了8个钩子函数,每个HOOK点有两个。这些钩子函数可分为入口(PRE_ROUTING和LOCAL_IN)和出口(LOCAL_OUT和POST_ROUTING)两大类,这篇笔记来看看这些钩子函数的实现。
相关代码文件有:
代码路径 | 说明 |
---|
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | AF_INET协议族在连接跟踪子系统中L3协议的实现 |
net/netfilter/nf_conntrack_core.c | 连接跟踪子系统框架对连接跟踪流程的核心实现 |
1. ipv4_conntrack_defrag()
连接跟踪子系统的两个入口处(PRE_ROUTING和LOCAL_IN)都注册了该钩子函数。
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
if (skb->nfct)
return NF_ACCEPT;
if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
if (nf_ct_ipv4_gather_frags(skb, hooknum == NF_INET_PRE_ROUTING ?
IP_DEFRAG_CONNTRACK_IN : IP_DEFRAG_CONNTRACK_OUT)) {
return NF_STOLEN;
}
}
return NF_ACCEPT;
}
可以看出,ipv4_conntrack_defrag()完成的工作就是重组IP报文,该钩子函数以较高优先级工作在连接跟踪子系统的入口处,这样可以保证连接跟踪子系统后面见到的报文都是完整的IP报文,也就是说连接跟踪子系统不处理IP分片。
2. ipv4_conntrack_in()
该钩子函数是连接跟踪子系统在PRE_ROUTING处注册的第二个钩子,它的优先级比ipv4_conntrack_defrag()低,它将完成AF_INET协议族数据包在连接跟踪子系统入口处要做的所有事情。
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(PF_INET, hooknum, skb);
}
直接调用连接跟踪子系统框架的入口处理函数,该函数的具体分析见笔记连接跟踪子系统之核心实现。这里要做的事情简单来说就是对该数据包进行跟踪,使其属于某个“连接”。
3. ipv4_conntrack_local()
该钩子函数是连接跟踪子系统在LOCAL_OUT处注册的第二个钩子。
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 *))
{
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ipt_hook: happy cracking.\n");
return NF_ACCEPT;
}
return nf_conntrack_in(PF_INET, hooknum, skb);
}
4. ipv4_conntrack_help()
该钩子函数是连接跟踪子系统在出口处注册的第一个钩子函数,两个出口LOCAL_OUT和POST_ROUTING都注册了该钩子。
static unsigned int ipv4_conntrack_help(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_conn_help *help;
const struct nf_conntrack_helper *helper;
ct = nf_ct_get(skb, &ctinfo);
if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
return NF_ACCEPT;
help = nfct_help(ct);
if (!help)
return NF_ACCEPT;
helper = rcu_dereference(help->helper);
if (!helper)
return NF_ACCEPT;
return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo);
}
从实现上可以看出,help()回调是可选的,可以有也可以没有。关于连接跟踪子系统给的helper机制,会有专门的笔记分析。
5. ipv4_confirm()
该钩子函数是连接跟踪子系统在出口处注册的第二个钩子函数,两个出口LOCAL_OUT和POST_ROUTING都注册了该钩子。
static unsigned int ipv4_confirm(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_confirm(skb);
}
nf_conntrack_confirm()的具体分析见笔记连接跟踪子系统之核心实现。简单来说,这里要做的事情就是将“新连接”的连接跟踪信息块加入到全局的连接信息块哈希表(nf_conntrack_hash)中,之所以需要这一步是因为新连接的识别是在PRE_ROUTING和LOCAL_OUT处,并且这两处的钩子函数优先级较高,此时数据包还没有过防火墙,而确认钩子函数以较低优先级位于防火墙之后,到了这里,说明数据包不会被丢弃了,此时再将其连接加入全局的连接跟踪哈希表是最合适的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)