⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nf_queue.c

📁 linux 内核源代码
💻 C
字号:
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/proc_fs.h>#include <linux/skbuff.h>#include <linux/netfilter.h>#include <linux/seq_file.h>#include <linux/rcupdate.h>#include <net/protocol.h>#include "nf_internals.h"/* * A queue handler may be registered for each protocol.  Each is protected by * long term mutex.  The handler must provide an an outfn() to accept packets * for queueing and must reinject all packets it receives, no matter what. */static struct nf_queue_handler *queue_handler[NPROTO];static DEFINE_MUTEX(queue_handler_mutex);/* return EBUSY when somebody else is registered, return EEXIST if the * same handler is registered, return 0 in case of success. */int nf_register_queue_handler(int pf, struct nf_queue_handler *qh){	int ret;	if (pf >= NPROTO)		return -EINVAL;	mutex_lock(&queue_handler_mutex);	if (queue_handler[pf] == qh)		ret = -EEXIST;	else if (queue_handler[pf])		ret = -EBUSY;	else {		rcu_assign_pointer(queue_handler[pf], qh);		ret = 0;	}	mutex_unlock(&queue_handler_mutex);	return ret;}EXPORT_SYMBOL(nf_register_queue_handler);/* The caller must flush their queue before this */int nf_unregister_queue_handler(int pf, struct nf_queue_handler *qh){	if (pf >= NPROTO)		return -EINVAL;	mutex_lock(&queue_handler_mutex);	if (queue_handler[pf] != qh) {		mutex_unlock(&queue_handler_mutex);		return -EINVAL;	}	rcu_assign_pointer(queue_handler[pf], NULL);	mutex_unlock(&queue_handler_mutex);	synchronize_rcu();	return 0;}EXPORT_SYMBOL(nf_unregister_queue_handler);void nf_unregister_queue_handlers(struct nf_queue_handler *qh){	int pf;	mutex_lock(&queue_handler_mutex);	for (pf = 0; pf < NPROTO; pf++)  {		if (queue_handler[pf] == qh)			rcu_assign_pointer(queue_handler[pf], NULL);	}	mutex_unlock(&queue_handler_mutex);	synchronize_rcu();}EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);/* * Any packet that leaves via this function must come back * through nf_reinject(). */static int __nf_queue(struct sk_buff *skb,		      struct list_head *elem,		      int pf, unsigned int hook,		      struct net_device *indev,		      struct net_device *outdev,		      int (*okfn)(struct sk_buff *),		      unsigned int queuenum){	int status;	struct nf_info *info;#ifdef CONFIG_BRIDGE_NETFILTER	struct net_device *physindev = NULL;	struct net_device *physoutdev = NULL;#endif	struct nf_afinfo *afinfo;	struct nf_queue_handler *qh;	/* QUEUE == DROP if noone is waiting, to be safe. */	rcu_read_lock();	qh = rcu_dereference(queue_handler[pf]);	if (!qh) {		rcu_read_unlock();		kfree_skb(skb);		return 1;	}	afinfo = nf_get_afinfo(pf);	if (!afinfo) {		rcu_read_unlock();		kfree_skb(skb);		return 1;	}	info = kmalloc(sizeof(*info) + afinfo->route_key_size, GFP_ATOMIC);	if (!info) {		if (net_ratelimit())			printk(KERN_ERR "OOM queueing packet %p\n",			       skb);		rcu_read_unlock();		kfree_skb(skb);		return 1;	}	*info = (struct nf_info) {		(struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };	/* If it's going away, ignore hook. */	if (!try_module_get(info->elem->owner)) {		rcu_read_unlock();		kfree(info);		return 0;	}	/* Bump dev refs so they don't vanish while packet is out */	if (indev) dev_hold(indev);	if (outdev) dev_hold(outdev);#ifdef CONFIG_BRIDGE_NETFILTER	if (skb->nf_bridge) {		physindev = skb->nf_bridge->physindev;		if (physindev) dev_hold(physindev);		physoutdev = skb->nf_bridge->physoutdev;		if (physoutdev) dev_hold(physoutdev);	}#endif	afinfo->saveroute(skb, info);	status = qh->outfn(skb, info, queuenum, qh->data);	rcu_read_unlock();	if (status < 0) {		/* James M doesn't say fuck enough. */		if (indev) dev_put(indev);		if (outdev) dev_put(outdev);#ifdef CONFIG_BRIDGE_NETFILTER		if (physindev) dev_put(physindev);		if (physoutdev) dev_put(physoutdev);#endif		module_put(info->elem->owner);		kfree(info);		kfree_skb(skb);		return 1;	}	return 1;}int nf_queue(struct sk_buff *skb,	     struct list_head *elem,	     int pf, unsigned int hook,	     struct net_device *indev,	     struct net_device *outdev,	     int (*okfn)(struct sk_buff *),	     unsigned int queuenum){	struct sk_buff *segs;	if (!skb_is_gso(skb))		return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn,				  queuenum);	switch (pf) {	case AF_INET:		skb->protocol = htons(ETH_P_IP);		break;	case AF_INET6:		skb->protocol = htons(ETH_P_IPV6);		break;	}	segs = skb_gso_segment(skb, 0);	kfree_skb(skb);	if (unlikely(IS_ERR(segs)))		return 1;	do {		struct sk_buff *nskb = segs->next;		segs->next = NULL;		if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn,				queuenum))			kfree_skb(segs);		segs = nskb;	} while (segs);	return 1;}void nf_reinject(struct sk_buff *skb, struct nf_info *info,		 unsigned int verdict){	struct list_head *elem = &info->elem->list;	struct list_head *i;	struct nf_afinfo *afinfo;	rcu_read_lock();	/* Release those devices we held, or Alexey will kill me. */	if (info->indev) dev_put(info->indev);	if (info->outdev) dev_put(info->outdev);#ifdef CONFIG_BRIDGE_NETFILTER	if (skb->nf_bridge) {		if (skb->nf_bridge->physindev)			dev_put(skb->nf_bridge->physindev);		if (skb->nf_bridge->physoutdev)			dev_put(skb->nf_bridge->physoutdev);	}#endif	/* Drop reference to owner of hook which queued us. */	module_put(info->elem->owner);	list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {		if (i == elem)			break;	}	if (i == &nf_hooks[info->pf][info->hook]) {		/* The module which sent it to userspace is gone. */		NFDEBUG("%s: module disappeared, dropping packet.\n",			__FUNCTION__);		verdict = NF_DROP;	}	/* Continue traversal iff userspace said ok... */	if (verdict == NF_REPEAT) {		elem = elem->prev;		verdict = NF_ACCEPT;	}	if (verdict == NF_ACCEPT) {		afinfo = nf_get_afinfo(info->pf);		if (!afinfo || afinfo->reroute(skb, info) < 0)			verdict = NF_DROP;	}	if (verdict == NF_ACCEPT) {	next_hook:		verdict = nf_iterate(&nf_hooks[info->pf][info->hook],				     skb, info->hook,				     info->indev, info->outdev, &elem,				     info->okfn, INT_MIN);	}	switch (verdict & NF_VERDICT_MASK) {	case NF_ACCEPT:	case NF_STOP:		info->okfn(skb);	case NF_STOLEN:		break;	case NF_QUEUE:		if (!__nf_queue(skb, elem, info->pf, info->hook,				info->indev, info->outdev, info->okfn,				verdict >> NF_VERDICT_BITS))			goto next_hook;		break;	default:		kfree_skb(skb);	}	rcu_read_unlock();	kfree(info);	return;}EXPORT_SYMBOL(nf_reinject);#ifdef CONFIG_PROC_FSstatic void *seq_start(struct seq_file *seq, loff_t *pos){	if (*pos >= NPROTO)		return NULL;	return pos;}static void *seq_next(struct seq_file *s, void *v, loff_t *pos){	(*pos)++;	if (*pos >= NPROTO)		return NULL;	return pos;}static void seq_stop(struct seq_file *s, void *v){}static int seq_show(struct seq_file *s, void *v){	int ret;	loff_t *pos = v;	struct nf_queue_handler *qh;	rcu_read_lock();	qh = rcu_dereference(queue_handler[*pos]);	if (!qh)		ret = seq_printf(s, "%2lld NONE\n", *pos);	else		ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);	rcu_read_unlock();	return ret;}static const struct seq_operations nfqueue_seq_ops = {	.start	= seq_start,	.next	= seq_next,	.stop	= seq_stop,	.show	= seq_show,};static int nfqueue_open(struct inode *inode, struct file *file){	return seq_open(file, &nfqueue_seq_ops);}static const struct file_operations nfqueue_file_ops = {	.owner	 = THIS_MODULE,	.open	 = nfqueue_open,	.read	 = seq_read,	.llseek	 = seq_lseek,	.release = seq_release,};#endif /* PROC_FS */int __init netfilter_queue_init(void){#ifdef CONFIG_PROC_FS	struct proc_dir_entry *pde;	pde = create_proc_entry("nf_queue", S_IRUGO, proc_net_netfilter);	if (!pde)		return -1;	pde->proc_fops = &nfqueue_file_ops;#endif	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -