连接跟踪子系统之AF_INET协议族钩子函数

如笔记连接跟踪子系统之AF_INET初始化所述,为了支持连接跟踪子系统,AF_INET协议族在4个HOOK点共注册了8个钩子函数,每个HOOK点有两个。这些钩子函数可分为入口(PRE_ROUTING和LOCAL_IN)和出口(LOCAL_OUT和POST_ROUTING)两大类,这篇笔记来看看这些钩子函数的实现。

相关代码文件有:

代码路径说明
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.cAF_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 *))
{
	//对于loopback这样的环回设备,连接跟踪模块在LOCAL_OUT点已经处理过了该skb
	if (skb->nfct)
		return NF_ACCEPT;
	//输入的skb是一个IP报文的分片
	if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
		//尝试将skb和已缓存skb进行IP片段重组
		if (nf_ct_ipv4_gather_frags(skb, hooknum == NF_INET_PRE_ROUTING ?
					    IP_DEFRAG_CONNTRACK_IN : IP_DEFRAG_CONNTRACK_OUT)) {
			//重组失败,给Netfilter框架返回NF_STOLEN,表示该skb被钩子内部消耗了,
			//无需协议族进一步处理,这会导致Netfilter框架结束整个HOOK点的遍历
			return NF_STOLEN;
		}
	}
	//skb是一个完整的IP报文或者重组成功,返回NF_ACCEPT
	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 *))
{
	//skb长度比IP首部还小,这应该属于RAW socket,不跟踪这种数据包
	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;

	//在入口处,skb应该已经找到了它的连接跟踪信息块
	ct = nf_ct_get(skb, &ctinfo);
	//没有ct,说明该skb没有被跟踪或者不属于任何一个连接。或者skb属于一个期望连接。
	//这两种情况,不会对该skb执行help()回调
	if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)
		return NF_ACCEPT;
	//获取skb的help信息,该信息在连接跟踪的入口处就已经指定了(如果有的话)
	help = nfct_help(ct);
	if (!help)
		return NF_ACCEPT;
	/* rcu_read_lock()ed by nf_hook_slow */
	helper = rcu_dereference(help->helper);
	if (!helper)
		return NF_ACCEPT;
	//执行help()回调,回调函数的返回值将作为给Netfilter框架的返回值
	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处,并且这两处的钩子函数优先级较高,此时数据包还没有过防火墙,而确认钩子函数以较低优先级位于防火墙之后,到了这里,说明数据包不会被丢弃了,此时再将其连接加入全局的连接跟踪哈希表是最合适的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值