netfiler源代码分析之框架介绍

netfiler框架是在内核协议栈实现的基础上完成的,在报文从网口接收,路由等方法实现基础上使用NF_HOOK调用相应的钩子来进入netfiler框架的处理,如

ip_rcv之后会调用NF_HOOK(NF_IP_PRE_ROUTING)

NF_HOOK宏定义如下:

 

#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) 
	NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)

#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh)	       
({int __ret;								       
if ((__ret=nf_hook_thresh(pf, hook, &(skb), indev, outdev, okfn, thresh, 1)) == 1)
	__ret = (okfn)(skb);						       
__ret;})

static inline int nf_hook_thresh(int pf, unsigned int hook,
				 struct sk_buff **pskb,
				 struct net_device *indev,
				 struct net_device *outdev,
				 int (*okfn)(struct sk_buff *), int thresh,
				 int cond)
{
	if (!cond)
		return 1;
#ifndef CONFIG_NETFILTER_DEBUG
	if (list_empty(&nf_hooks[pf][hook]))
		return 1;
#endif
	return nf_hook_slow(pf, hook, pskb, indev, outdev, okfn, thresh);
}

 

重点介绍下nf_hook_slow方法。

 

nf_hook_slow针对调用NF_HOOK时的hook点,遍历所有的钩子函数并判断匹配(match)及完成相应处理(target)

 

int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
		 struct net_device *indev,
		 struct net_device *outdev,
		 int (*okfn)(struct sk_buff *),
		 int hook_thresh)
{
	struct list_head *elem;
	unsigned int verdict;
	int ret = 0;

	/* We may already have this, but read-locks nest anyway */
	rcu_read_lock();

	elem = &nf_hooks[pf][hook];
next_hook:
	verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
			     outdev, &elem, okfn, hook_thresh);
	if (verdict == NF_ACCEPT || verdict == NF_STOP) {
		ret = 1;
		goto unlock;
	} else if (verdict == NF_DROP) {
		kfree_skb(*pskb);
		ret = -EPERM;
	} else if ((verdict & NF_VERDICT_MASK)  == NF_QUEUE) {
		NFDEBUG("nf_hook: Verdict = QUEUE.
");
		if (!nf_queue(*pskb, elem, pf, hook, indev, outdev, okfn,
			      verdict >> NF_VERDICT_BITS))
			goto next_hook;
	}
unlock:
	rcu_read_unlock();
	return ret;
}

 

选择hook对应的钩子函数时,使用了 nf_hooksstruct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]二维数组,其中行定义了协议簇类型,最大为NPROTO33),列定义了不同的hook,具体内容如下所示(参考netfilter_ipv4.h)

 

#define NF_IP_PRE_ROUTING 0

/* If the packet is destined for this box. */

#define NF_IP_LOCAL_IN 1

/* If the packet is destined for another interface. */

#define NF_IP_FORWARD 2

/* Packets coming from a local process. */

#define NF_IP_LOCAL_OUT 3

/* Packets about to hit the wire. */

#define NF_IP_POST_ROUTING 4

 

下面针对每个HOOK点列举下协议栈中的调用

1. ip_rcv中调用NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish)

网卡接收ip报文后经过pre_routing hook点处理。此hook点一般是用来做DNAT。

2. ip_local_deliver中调用NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,ip_local_deliver_finish)

ip报文被本地网卡接收后,经过local_in hook点处理

3. ip_forward中调用NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev, ip_forward_finish)

路由查询后不是本地数据,需要做转发处理,经过forward hook点处理

4. ip_push_pending_frames中调用NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,dst_output)

此处理是将ip分片报文重组后送出去

5. ip_output中调用NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,ip_finish_output,!(IPCB(skb)->flags & IPSKB_REROUTED))

如果报文中没有设置IPSKB_REROUTED标志,则报文会过post_routing hook点处理。此hook点一般是用来做SNAT的。

 

NEXT: 后面会介绍netfilter框架如何注册hook钩子。

 

原文地址:https://www.cnblogs.com/haoqingchuan/p/6240483.html