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

📄 arp_tables.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	unsigned int hook;	/* No recursion; use packet counter to save back ptrs (reset	 * to 0 as we leave), and comefrom to save source hook bitmask.	 */	for (hook = 0; hook < NF_ARP_NUMHOOKS; hook++) {		unsigned int pos = newinfo->hook_entry[hook];		struct arpt_entry *e			= (struct arpt_entry *)(newinfo->entries + pos);		if (!(valid_hooks & (1 << hook)))			continue;		/* Set initial back pointer. */		e->counters.pcnt = pos;		for (;;) {			struct arpt_standard_target *t				= (void *)arpt_get_target(e);			if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {				printk("arptables: loop hook %u pos %u %08X.\n",				       hook, pos, e->comefrom);				return 0;			}			e->comefrom				|= ((1 << hook) | (1 << NF_ARP_NUMHOOKS));			/* Unconditional return/END. */			if (e->target_offset == sizeof(struct arpt_entry)			    && (strcmp(t->target.u.user.name,				       ARPT_STANDARD_TARGET) == 0)			    && t->verdict < 0			    && unconditional(&e->arp)) {				unsigned int oldpos, size;				/* Return: backtrack through the last				 * big jump.				 */				do {					e->comefrom ^= (1<<NF_ARP_NUMHOOKS);					oldpos = pos;					pos = e->counters.pcnt;					e->counters.pcnt = 0;					/* We're at the start. */					if (pos == oldpos)						goto next;					e = (struct arpt_entry *)						(newinfo->entries + pos);				} while (oldpos == pos + e->next_offset);				/* Move along one */				size = e->next_offset;				e = (struct arpt_entry *)					(newinfo->entries + pos + size);				e->counters.pcnt = pos;				pos += size;			} else {				int newpos = t->verdict;				if (strcmp(t->target.u.user.name,					   ARPT_STANDARD_TARGET) == 0				    && newpos >= 0) {					/* This a jump; chase it. */					duprintf("Jump rule %u -> %u\n",						 pos, newpos);				} else {					/* ... this is a fallthru */					newpos = pos + e->next_offset;				}				e = (struct arpt_entry *)					(newinfo->entries + newpos);				e->counters.pcnt = pos;				pos = newpos;			}		}		next:		duprintf("Finished chain %u\n", hook);	}	return 1;}static inline int standard_check(const struct arpt_entry_target *t,				 unsigned int max_offset){	struct arpt_standard_target *targ = (void *)t;	/* Check standard info. */	if (t->u.target_size	    != ARPT_ALIGN(sizeof(struct arpt_standard_target))) {		duprintf("arpt_standard_check: target size %u != %Zu\n",			 t->u.target_size,			 ARPT_ALIGN(sizeof(struct arpt_standard_target)));		return 0;	}	if (targ->verdict >= 0	    && targ->verdict > max_offset - sizeof(struct arpt_entry)) {		duprintf("arpt_standard_check: bad verdict (%i)\n",			 targ->verdict);		return 0;	}	if (targ->verdict < -NF_MAX_VERDICT - 1) {		duprintf("arpt_standard_check: bad negative verdict (%i)\n",			 targ->verdict);		return 0;	}	return 1;}static struct arpt_target arpt_standard_target;static inline int check_entry(struct arpt_entry *e, const char *name, unsigned int size,			      unsigned int *i){	struct arpt_entry_target *t;	struct arpt_target *target;	int ret;	if (!arp_checkentry(&e->arp)) {		duprintf("arp_tables: arp check failed %p %s.\n", e, name);		return -EINVAL;	}	t = arpt_get_target(e);	target = try_then_request_module(find_target(t->u.user.name,						     t->u.user.revision),					 "arpt_%s", t->u.user.name);	if (IS_ERR(target) || !target) {		duprintf("check_entry: `%s' not found\n", t->u.user.name);		ret = target ? PTR_ERR(target) : -ENOENT;		goto out;	}	t->u.kernel.target = target;	if (t->u.kernel.target == &arpt_standard_target) {		if (!standard_check(t, size)) {			ret = -EINVAL;			goto out;		}	} else if (t->u.kernel.target->checkentry		   && !t->u.kernel.target->checkentry(name, e, t->data,						      t->u.target_size						      - sizeof(*t),						      e->comefrom)) {		module_put(t->u.kernel.target->me);		duprintf("arp_tables: check failed for `%s'.\n",			 t->u.kernel.target->name);		ret = -EINVAL;		goto out;	}	(*i)++;	return 0;out:	return ret;}static inline int check_entry_size_and_hooks(struct arpt_entry *e,					     struct arpt_table_info *newinfo,					     unsigned char *base,					     unsigned char *limit,					     const unsigned int *hook_entries,					     const unsigned int *underflows,					     unsigned int *i){	unsigned int h;	if ((unsigned long)e % __alignof__(struct arpt_entry) != 0	    || (unsigned char *)e + sizeof(struct arpt_entry) >= limit) {		duprintf("Bad offset %p\n", e);		return -EINVAL;	}	if (e->next_offset	    < sizeof(struct arpt_entry) + sizeof(struct arpt_entry_target)) {		duprintf("checking: element %p size %u\n",			 e, e->next_offset);		return -EINVAL;	}	/* Check hooks & underflows */	for (h = 0; h < NF_ARP_NUMHOOKS; h++) {		if ((unsigned char *)e - base == hook_entries[h])			newinfo->hook_entry[h] = hook_entries[h];		if ((unsigned char *)e - base == underflows[h])			newinfo->underflow[h] = underflows[h];	}	/* FIXME: underflows must be unconditional, standard verdicts           < 0 (not ARPT_RETURN). --RR */	/* Clear counters and comefrom */	e->counters = ((struct arpt_counters) { 0, 0 });	e->comefrom = 0;	(*i)++;	return 0;}static inline int cleanup_entry(struct arpt_entry *e, unsigned int *i){	struct arpt_entry_target *t;	if (i && (*i)-- == 0)		return 1;	t = arpt_get_target(e);	if (t->u.kernel.target->destroy)		t->u.kernel.target->destroy(t->data,					    t->u.target_size - sizeof(*t));	module_put(t->u.kernel.target->me);	return 0;}/* Checks and translates the user-supplied table segment (held in * newinfo). */static int translate_table(const char *name,			   unsigned int valid_hooks,			   struct arpt_table_info *newinfo,			   unsigned int size,			   unsigned int number,			   const unsigned int *hook_entries,			   const unsigned int *underflows){	unsigned int i;	int ret;	newinfo->size = size;	newinfo->number = number;	/* Init all hooks to impossible value. */	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {		newinfo->hook_entry[i] = 0xFFFFFFFF;		newinfo->underflow[i] = 0xFFFFFFFF;	}	duprintf("translate_table: size %u\n", newinfo->size);	i = 0;	/* Walk through entries, checking offsets. */	ret = ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size,				 check_entry_size_and_hooks,				 newinfo,				 newinfo->entries,				 newinfo->entries + size,				 hook_entries, underflows, &i);	duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret);	if (ret != 0)		return ret;	if (i != number) {		duprintf("translate_table: %u not %u entries\n",			 i, number);		return -EINVAL;	}	/* Check hooks all assigned */	for (i = 0; i < NF_ARP_NUMHOOKS; i++) {		/* Only hooks which are valid */		if (!(valid_hooks & (1 << i)))			continue;		if (newinfo->hook_entry[i] == 0xFFFFFFFF) {			duprintf("Invalid hook entry %u %u\n",				 i, hook_entries[i]);			return -EINVAL;		}		if (newinfo->underflow[i] == 0xFFFFFFFF) {			duprintf("Invalid underflow %u %u\n",				 i, underflows[i]);			return -EINVAL;		}	}	if (!mark_source_chains(newinfo, valid_hooks)) {		duprintf("Looping hook\n");		return -ELOOP;	}	/* Finally, each sanity check must pass */	i = 0;	ret = ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size,				 check_entry, name, size, &i);	if (ret != 0) {		ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size,				   cleanup_entry, &i);		return ret;	}	/* And one copy for every other CPU */	for_each_cpu(i) {		if (i == 0)			continue;		memcpy(newinfo->entries + SMP_ALIGN(newinfo->size) * i,		       newinfo->entries,		       SMP_ALIGN(newinfo->size));	}	return ret;}static struct arpt_table_info *replace_table(struct arpt_table *table,					     unsigned int num_counters,					     struct arpt_table_info *newinfo,					     int *error){	struct arpt_table_info *oldinfo;	/* Do the substitution. */	write_lock_bh(&table->lock);	/* Check inside lock: is the old number correct? */	if (num_counters != table->private->number) {		duprintf("num_counters != table->private->number (%u/%u)\n",			 num_counters, table->private->number);		write_unlock_bh(&table->lock);		*error = -EAGAIN;		return NULL;	}	oldinfo = table->private;	table->private = newinfo;	newinfo->initial_entries = oldinfo->initial_entries;	write_unlock_bh(&table->lock);	return oldinfo;}/* Gets counters. */static inline int add_entry_to_counter(const struct arpt_entry *e,				       struct arpt_counters total[],				       unsigned int *i){	ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);	(*i)++;	return 0;}static void get_counters(const struct arpt_table_info *t,			 struct arpt_counters counters[]){	unsigned int cpu;	unsigned int i;	for_each_cpu(cpu) {		i = 0;		ARPT_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),				   t->size,				   add_entry_to_counter,				   counters,				   &i);	}}static int copy_entries_to_user(unsigned int total_size,				struct arpt_table *table,				void __user *userptr){	unsigned int off, num, countersize;	struct arpt_entry *e;	struct arpt_counters *counters;	int ret = 0;	/* We need atomic snapshot of counters: rest doesn't change	 * (other than comefrom, which userspace doesn't care	 * about).	 */	countersize = sizeof(struct arpt_counters) * table->private->number;	counters = vmalloc(countersize);	if (counters == NULL)		return -ENOMEM;	/* First, sum counters... */	memset(counters, 0, countersize);	write_lock_bh(&table->lock);	get_counters(table->private, counters);	write_unlock_bh(&table->lock);	/* ... then copy entire thing from CPU 0... */	if (copy_to_user(userptr, table->private->entries, total_size) != 0) {		ret = -EFAULT;		goto free_counters;	}	/* FIXME: use iterator macros --RR */	/* ... then go back and fix counters and names */	for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){		struct arpt_entry_target *t;		e = (struct arpt_entry *)(table->private->entries + off);		if (copy_to_user(userptr + off				 + offsetof(struct arpt_entry, counters),				 &counters[num],				 sizeof(counters[num])) != 0) {			ret = -EFAULT;			goto free_counters;		}		t = arpt_get_target(e);		if (copy_to_user(userptr + off + e->target_offset				 + offsetof(struct arpt_entry_target,					    u.user.name),				 t->u.kernel.target->name,				 strlen(t->u.kernel.target->name)+1) != 0) {			ret = -EFAULT;			goto free_counters;		}	} free_counters:	vfree(counters);	return ret;}static int get_entries(const struct arpt_get_entries *entries,		       struct arpt_get_entries __user *uptr){	int ret;	struct arpt_table *t;	t = find_table_lock(entries->name);	if (t || !IS_ERR(t)) {		duprintf("t->private->number = %u\n",			 t->private->number);		if (entries->size == t->private->size)			ret = copy_entries_to_user(t->private->size,						   t, uptr->entrytable);		else {			duprintf("get_entries: I've got %u not %u!\n",				 t->private->size,				 entries->size);			ret = -EINVAL;		}		module_put(t->me);		up(&arpt_mutex);	} else		ret = t ? PTR_ERR(t) : -ENOENT;	return ret;}static int do_replace(void __user *user, unsigned int len){	int ret;	struct arpt_replace tmp;	struct arpt_table *t;	struct arpt_table_info *newinfo, *oldinfo;	struct arpt_counters *counters;	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)		return -EFAULT;	/* Hack: Causes ipchains to give correct error msg --RR */	if (len != sizeof(tmp) + tmp.size)		return -ENOPROTOOPT;	/* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */	if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)		return -ENOMEM;

⌨️ 快捷键说明

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