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

📄 xt_hashlimit.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		if (!(hinfo->cfg.mode &		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))			return 0;		nexthdr = ip_hdr(skb)->protocol;		break;#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)	case AF_INET6:		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DIP)			memcpy(&dst->addr.ip6.dst, &ipv6_hdr(skb)->daddr,			       sizeof(dst->addr.ip6.dst));		if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SIP)			memcpy(&dst->addr.ip6.src, &ipv6_hdr(skb)->saddr,			       sizeof(dst->addr.ip6.src));		if (!(hinfo->cfg.mode &		      (XT_HASHLIMIT_HASH_DPT | XT_HASHLIMIT_HASH_SPT)))			return 0;		nexthdr = ipv6_find_hdr(skb, &protoff, -1, NULL);		if (nexthdr < 0)			return -1;		break;#endif	default:		BUG();		return 0;	}	switch (nexthdr) {	case IPPROTO_TCP:	case IPPROTO_UDP:	case IPPROTO_UDPLITE:	case IPPROTO_SCTP:	case IPPROTO_DCCP:		ports = skb_header_pointer(skb, protoff, sizeof(_ports),					   &_ports);		break;	default:		_ports[0] = _ports[1] = 0;		ports = _ports;		break;	}	if (!ports)		return -1;	if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_SPT)		dst->src_port = ports[0];	if (hinfo->cfg.mode & XT_HASHLIMIT_HASH_DPT)		dst->dst_port = ports[1];	return 0;}static boolhashlimit_match(const struct sk_buff *skb,		const struct net_device *in,		const struct net_device *out,		const struct xt_match *match,		const void *matchinfo,		int offset,		unsigned int protoff,		bool *hotdrop){	const struct xt_hashlimit_info *r =		((const struct xt_hashlimit_info *)matchinfo)->u.master;	struct xt_hashlimit_htable *hinfo = r->hinfo;	unsigned long now = jiffies;	struct dsthash_ent *dh;	struct dsthash_dst dst;	if (hashlimit_init_dst(hinfo, &dst, skb, protoff) < 0)		goto hotdrop;	spin_lock_bh(&hinfo->lock);	dh = dsthash_find(hinfo, &dst);	if (!dh) {		dh = dsthash_alloc_init(hinfo, &dst);		if (!dh) {			spin_unlock_bh(&hinfo->lock);			goto hotdrop;		}		dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);		dh->rateinfo.prev = jiffies;		dh->rateinfo.credit = user2credits(hinfo->cfg.avg *						   hinfo->cfg.burst);		dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *						       hinfo->cfg.burst);		dh->rateinfo.cost = user2credits(hinfo->cfg.avg);	} else {		/* update expiration timeout */		dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);		rateinfo_recalc(dh, now);	}	if (dh->rateinfo.credit >= dh->rateinfo.cost) {		/* We're underlimit. */		dh->rateinfo.credit -= dh->rateinfo.cost;		spin_unlock_bh(&hinfo->lock);		return true;	}	spin_unlock_bh(&hinfo->lock);	/* default case: we're overlimit, thus don't match */	return false;hotdrop:	*hotdrop = true;	return false;}static boolhashlimit_checkentry(const char *tablename,		     const void *inf,		     const struct xt_match *match,		     void *matchinfo,		     unsigned int hook_mask){	struct xt_hashlimit_info *r = matchinfo;	/* Check for overflow. */	if (r->cfg.burst == 0 ||	    user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) {		printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",		       r->cfg.avg, r->cfg.burst);		return false;	}	if (r->cfg.mode == 0 ||	    r->cfg.mode > (XT_HASHLIMIT_HASH_DPT |			   XT_HASHLIMIT_HASH_DIP |			   XT_HASHLIMIT_HASH_SIP |			   XT_HASHLIMIT_HASH_SPT))		return false;	if (!r->cfg.gc_interval)		return false;	if (!r->cfg.expire)		return false;	if (r->name[sizeof(r->name) - 1] != '\0')		return false;	/* This is the best we've got: We cannot release and re-grab lock,	 * since checkentry() is called before x_tables.c grabs xt_mutex.	 * We also cannot grab the hashtable spinlock, since htable_create will	 * call vmalloc, and that can sleep.  And we cannot just re-search	 * the list of htable's in htable_create(), since then we would	 * create duplicate proc files. -HW */	mutex_lock(&hlimit_mutex);	r->hinfo = htable_find_get(r->name, match->family);	if (!r->hinfo && htable_create(r, match->family) != 0) {		mutex_unlock(&hlimit_mutex);		return false;	}	mutex_unlock(&hlimit_mutex);	/* Ugly hack: For SMP, we only want to use one set */	r->u.master = r;	return true;}static voidhashlimit_destroy(const struct xt_match *match, void *matchinfo){	const struct xt_hashlimit_info *r = matchinfo;	htable_put(r->hinfo);}#ifdef CONFIG_COMPATstruct compat_xt_hashlimit_info {	char name[IFNAMSIZ];	struct hashlimit_cfg cfg;	compat_uptr_t hinfo;	compat_uptr_t master;};static void compat_from_user(void *dst, void *src){	int off = offsetof(struct compat_xt_hashlimit_info, hinfo);	memcpy(dst, src, off);	memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);}static int compat_to_user(void __user *dst, void *src){	int off = offsetof(struct compat_xt_hashlimit_info, hinfo);	return copy_to_user(dst, src, off) ? -EFAULT : 0;}#endifstatic struct xt_match xt_hashlimit[] __read_mostly = {	{		.name		= "hashlimit",		.family		= AF_INET,		.match		= hashlimit_match,		.matchsize	= sizeof(struct xt_hashlimit_info),#ifdef CONFIG_COMPAT		.compatsize	= sizeof(struct compat_xt_hashlimit_info),		.compat_from_user = compat_from_user,		.compat_to_user	= compat_to_user,#endif		.checkentry	= hashlimit_checkentry,		.destroy	= hashlimit_destroy,		.me		= THIS_MODULE	},	{		.name		= "hashlimit",		.family		= AF_INET6,		.match		= hashlimit_match,		.matchsize	= sizeof(struct xt_hashlimit_info),#ifdef CONFIG_COMPAT		.compatsize	= sizeof(struct compat_xt_hashlimit_info),		.compat_from_user = compat_from_user,		.compat_to_user	= compat_to_user,#endif		.checkentry	= hashlimit_checkentry,		.destroy	= hashlimit_destroy,		.me		= THIS_MODULE	},};/* PROC stuff */static void *dl_seq_start(struct seq_file *s, loff_t *pos){	struct proc_dir_entry *pde = s->private;	struct xt_hashlimit_htable *htable = pde->data;	unsigned int *bucket;	spin_lock_bh(&htable->lock);	if (*pos >= htable->cfg.size)		return NULL;	bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC);	if (!bucket)		return ERR_PTR(-ENOMEM);	*bucket = *pos;	return bucket;}static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos){	struct proc_dir_entry *pde = s->private;	struct xt_hashlimit_htable *htable = pde->data;	unsigned int *bucket = (unsigned int *)v;	*pos = ++(*bucket);	if (*pos >= htable->cfg.size) {		kfree(v);		return NULL;	}	return bucket;}static void dl_seq_stop(struct seq_file *s, void *v){	struct proc_dir_entry *pde = s->private;	struct xt_hashlimit_htable *htable = pde->data;	unsigned int *bucket = (unsigned int *)v;	kfree(bucket);	spin_unlock_bh(&htable->lock);}static int dl_seq_real_show(struct dsthash_ent *ent, int family,				   struct seq_file *s){	/* recalculate to show accurate numbers */	rateinfo_recalc(ent, jiffies);	switch (family) {	case AF_INET:		return seq_printf(s, "%ld %u.%u.%u.%u:%u->"				     "%u.%u.%u.%u:%u %u %u %u\n",				 (long)(ent->expires - jiffies)/HZ,				 NIPQUAD(ent->dst.addr.ip.src),				 ntohs(ent->dst.src_port),				 NIPQUAD(ent->dst.addr.ip.dst),				 ntohs(ent->dst.dst_port),				 ent->rateinfo.credit, ent->rateinfo.credit_cap,				 ent->rateinfo.cost);	case AF_INET6:		return seq_printf(s, "%ld " NIP6_FMT ":%u->"				     NIP6_FMT ":%u %u %u %u\n",				 (long)(ent->expires - jiffies)/HZ,				 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.src),				 ntohs(ent->dst.src_port),				 NIP6(*(struct in6_addr *)&ent->dst.addr.ip6.dst),				 ntohs(ent->dst.dst_port),				 ent->rateinfo.credit, ent->rateinfo.credit_cap,				 ent->rateinfo.cost);	default:		BUG();		return 0;	}}static int dl_seq_show(struct seq_file *s, void *v){	struct proc_dir_entry *pde = s->private;	struct xt_hashlimit_htable *htable = pde->data;	unsigned int *bucket = (unsigned int *)v;	struct dsthash_ent *ent;	struct hlist_node *pos;	if (!hlist_empty(&htable->hash[*bucket])) {		hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node)			if (dl_seq_real_show(ent, htable->family, s))				return 1;	}	return 0;}static const struct seq_operations dl_seq_ops = {	.start = dl_seq_start,	.next  = dl_seq_next,	.stop  = dl_seq_stop,	.show  = dl_seq_show};static int dl_proc_open(struct inode *inode, struct file *file){	int ret = seq_open(file, &dl_seq_ops);	if (!ret) {		struct seq_file *sf = file->private_data;		sf->private = PDE(inode);	}	return ret;}static const struct file_operations dl_file_ops = {	.owner   = THIS_MODULE,	.open    = dl_proc_open,	.read    = seq_read,	.llseek  = seq_lseek,	.release = seq_release};static int __init xt_hashlimit_init(void){	int err;	err = xt_register_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));	if (err < 0)		goto err1;	err = -ENOMEM;	hashlimit_cachep = kmem_cache_create("xt_hashlimit",					    sizeof(struct dsthash_ent), 0, 0,					    NULL);	if (!hashlimit_cachep) {		printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");		goto err2;	}	hashlimit_procdir4 = proc_mkdir("ipt_hashlimit", init_net.proc_net);	if (!hashlimit_procdir4) {		printk(KERN_ERR "xt_hashlimit: unable to create proc dir "				"entry\n");		goto err3;	}	hashlimit_procdir6 = proc_mkdir("ip6t_hashlimit", init_net.proc_net);	if (!hashlimit_procdir6) {		printk(KERN_ERR "xt_hashlimit: unable to create proc dir "				"entry\n");		goto err4;	}	return 0;err4:	remove_proc_entry("ipt_hashlimit", init_net.proc_net);err3:	kmem_cache_destroy(hashlimit_cachep);err2:	xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));err1:	return err;}static void __exit xt_hashlimit_fini(void){	remove_proc_entry("ipt_hashlimit", init_net.proc_net);	remove_proc_entry("ip6t_hashlimit", init_net.proc_net);	kmem_cache_destroy(hashlimit_cachep);	xt_unregister_matches(xt_hashlimit, ARRAY_SIZE(xt_hashlimit));}module_init(xt_hashlimit_init);module_exit(xt_hashlimit_fini);

⌨️ 快捷键说明

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