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

📄 ebtables.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  ebtables * *  Author: *  Bart De Schuymer		<bdschuym@pandora.be> * *  ebtables.c,v 2.0, July, 2002 * *  This code is stongly inspired on the iptables code which is *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  as published by the Free Software Foundation; either version *  2 of the License, or (at your option) any later version. *//* used for print_string */#include <linux/sched.h>#include <linux/tty.h>#include <linux/kmod.h>#include <linux/module.h>#include <linux/vmalloc.h>#include <linux/netfilter_bridge/ebtables.h>#include <linux/spinlock.h>#include <asm/uaccess.h>#include <linux/smp.h>#include <linux/cpumask.h>#include <net/sock.h>/* needed for logical [in,out]-dev filtering */#include "../br_private.h"/* list_named_find */#define ASSERT_READ_LOCK(x)#define ASSERT_WRITE_LOCK(x)#include <linux/netfilter_ipv4/listhelp.h>#if 0/* use this for remote debugging * Copyright (C) 1998 by Ori Pomerantz * Print the string to the appropriate tty, the one * the current task uses */static void print_string(char *str){	struct tty_struct *my_tty;	/* The tty for the current task */	my_tty = current->signal->tty;	if (my_tty != NULL) {		my_tty->driver->write(my_tty, 0, str, strlen(str));		my_tty->driver->write(my_tty, 0, "\015\012", 2);	}}#define BUGPRINT(args) print_string(args);#else#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\                                         "report to author: "format, ## args)/* #define BUGPRINT(format, args...) */#endif#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\                                         ": out of memory: "format, ## args)/* #define MEMPRINT(format, args...) *//* * Each cpu has its own set of counters, so there is no need for write_lock in * the softirq * For reading or updating the counters, the user context needs to * get a write_lock *//* The size of each set of counters is altered to get cache alignment */#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \   COUNTER_OFFSET(n) * cpu))static DECLARE_MUTEX(ebt_mutex);static LIST_HEAD(ebt_tables);static LIST_HEAD(ebt_targets);static LIST_HEAD(ebt_matches);static LIST_HEAD(ebt_watchers);static struct ebt_target ebt_standard_target ={ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};static inline int ebt_do_watcher (struct ebt_entry_watcher *w,   const struct sk_buff *skb, unsigned int hooknr, const struct net_device *in,   const struct net_device *out){	w->u.watcher->watcher(skb, hooknr, in, out, w->data,	   w->watcher_size);	/* watchers don't give a verdict */	return 0;}static inline int ebt_do_match (struct ebt_entry_match *m,   const struct sk_buff *skb, const struct net_device *in,   const struct net_device *out){	return m->u.match->match(skb, in, out, m->data,	   m->match_size);}static inline int ebt_dev_check(char *entry, const struct net_device *device){	int i = 0;	char *devname = device->name;	if (*entry == '\0')		return 0;	if (!device)		return 1;	/* 1 is the wildcard token */	while (entry[i] != '\0' && entry[i] != 1 && entry[i] == devname[i])		i++;	return (devname[i] != entry[i] && entry[i] != 1);}#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))/* process standard matches */static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,   const struct net_device *in, const struct net_device *out){	int verdict, i;	if (e->bitmask & EBT_802_3) {		if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))			return 1;	} else if (!(e->bitmask & EBT_NOPROTO) &&	   FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))		return 1;	if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))		return 1;	if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))		return 1;	if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(	   e->logical_in, in->br_port->br->dev), EBT_ILOGICALIN))		return 1;	if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(	   e->logical_out, out->br_port->br->dev), EBT_ILOGICALOUT))		return 1;	if (e->bitmask & EBT_SOURCEMAC) {		verdict = 0;		for (i = 0; i < 6; i++)			verdict |= (h->h_source[i] ^ e->sourcemac[i]) &			   e->sourcemsk[i];		if (FWINV2(verdict != 0, EBT_ISOURCE) )			return 1;	}	if (e->bitmask & EBT_DESTMAC) {		verdict = 0;		for (i = 0; i < 6; i++)			verdict |= (h->h_dest[i] ^ e->destmac[i]) &			   e->destmsk[i];		if (FWINV2(verdict != 0, EBT_IDEST) )			return 1;	}	return 0;}/* Do some firewalling */unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,   const struct net_device *in, const struct net_device *out,   struct ebt_table *table){	int i, nentries;	struct ebt_entry *point;	struct ebt_counter *counter_base, *cb_base;	struct ebt_entry_target *t;	int verdict, sp = 0;	struct ebt_chainstack *cs;	struct ebt_entries *chaininfo;	char *base;	struct ebt_table_info *private;	read_lock_bh(&table->lock);	private = table->private;	cb_base = COUNTER_BASE(private->counters, private->nentries,	   smp_processor_id());	if (private->chainstack)		cs = private->chainstack[smp_processor_id()];	else		cs = NULL;	chaininfo = private->hook_entry[hook];	nentries = private->hook_entry[hook]->nentries;	point = (struct ebt_entry *)(private->hook_entry[hook]->data);	counter_base = cb_base + private->hook_entry[hook]->counter_offset;	/* base for chain jumps */	base = private->entries;	i = 0;	while (i < nentries) {		if (ebt_basic_match(point, eth_hdr(*pskb), in, out))			goto letscontinue;		if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)			goto letscontinue;		/* increase counter */		(*(counter_base + i)).pcnt++;		(*(counter_base + i)).bcnt+=(**pskb).len;		/* these should only watch: not modify, nor tell us		   what to do with the packet */		EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, hook, in,		   out);		t = (struct ebt_entry_target *)		   (((char *)point) + point->target_offset);		/* standard target */		if (!t->u.target->target)			verdict = ((struct ebt_standard_target *)t)->verdict;		else			verdict = t->u.target->target(pskb, hook,			   in, out, t->data, t->target_size);		if (verdict == EBT_ACCEPT) {			read_unlock_bh(&table->lock);			return NF_ACCEPT;		}		if (verdict == EBT_DROP) {			read_unlock_bh(&table->lock);			return NF_DROP;		}		if (verdict == EBT_RETURN) {letsreturn:#ifdef CONFIG_NETFILTER_DEBUG			if (sp == 0) {				BUGPRINT("RETURN on base chain");				/* act like this is EBT_CONTINUE */				goto letscontinue;			}#endif			sp--;			/* put all the local variables right */			i = cs[sp].n;			chaininfo = cs[sp].chaininfo;			nentries = chaininfo->nentries;			point = cs[sp].e;			counter_base = cb_base +			   chaininfo->counter_offset;			continue;		}		if (verdict == EBT_CONTINUE)			goto letscontinue;#ifdef CONFIG_NETFILTER_DEBUG		if (verdict < 0) {			BUGPRINT("bogus standard verdict\n");			read_unlock_bh(&table->lock);			return NF_DROP;		}#endif		/* jump to a udc */		cs[sp].n = i + 1;		cs[sp].chaininfo = chaininfo;		cs[sp].e = (struct ebt_entry *)		   (((char *)point) + point->next_offset);		i = 0;		chaininfo = (struct ebt_entries *) (base + verdict);#ifdef CONFIG_NETFILTER_DEBUG		if (chaininfo->distinguisher) {			BUGPRINT("jump to non-chain\n");			read_unlock_bh(&table->lock);			return NF_DROP;		}#endif		nentries = chaininfo->nentries;		point = (struct ebt_entry *)chaininfo->data;		counter_base = cb_base + chaininfo->counter_offset;		sp++;		continue;letscontinue:		point = (struct ebt_entry *)		   (((char *)point) + point->next_offset);		i++;	}	/* I actually like this :) */	if (chaininfo->policy == EBT_RETURN)		goto letsreturn;	if (chaininfo->policy == EBT_ACCEPT) {		read_unlock_bh(&table->lock);		return NF_ACCEPT;	}	read_unlock_bh(&table->lock);	return NF_DROP;}/* If it succeeds, returns element and locks mutex */static inline void *find_inlist_lock_noload(struct list_head *head, const char *name, int *error,   struct semaphore *mutex){	void *ret;	*error = down_interruptible(mutex);	if (*error != 0)		return NULL;	ret = list_named_find(head, name);	if (!ret) {		*error = -ENOENT;		up(mutex);	}	return ret;}#ifndef CONFIG_KMOD#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))#elsestatic void *find_inlist_lock(struct list_head *head, const char *name, const char *prefix,   int *error, struct semaphore *mutex){	void *ret;	ret = find_inlist_lock_noload(head, name, error, mutex);	if (!ret) {		request_module("%s%s", prefix, name);		ret = find_inlist_lock_noload(head, name, error, mutex);	}	return ret;}#endifstatic inline struct ebt_table *find_table_lock(const char *name, int *error, struct semaphore *mutex){	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);}static inline struct ebt_match *find_match_lock(const char *name, int *error, struct semaphore *mutex){	return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);}static inline struct ebt_watcher *find_watcher_lock(const char *name, int *error, struct semaphore *mutex){	return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);}static inline struct ebt_target *find_target_lock(const char *name, int *error, struct semaphore *mutex){	return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);}static inline intebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,   const char *name, unsigned int hookmask, unsigned int *cnt){	struct ebt_match *match;	int ret;	if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >	   ((char *)e) + e->watchers_offset)		return -EINVAL;	match = find_match_lock(m->u.name, &ret, &ebt_mutex);	if (!match)		return ret;	m->u.match = match;	if (!try_module_get(match->me)) {		up(&ebt_mutex);		return -ENOENT;	}	up(&ebt_mutex);	if (match->check &&	   match->check(name, hookmask, e, m->data, m->match_size) != 0) {		BUGPRINT("match->check failed\n");		module_put(match->me);		return -EINVAL;	}	(*cnt)++;	return 0;}static inline intebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,   const char *name, unsigned int hookmask, unsigned int *cnt){	struct ebt_watcher *watcher;	int ret;	if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >	   ((char *)e) + e->target_offset)		return -EINVAL;	watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);	if (!watcher)		return ret;	w->u.watcher = watcher;	if (!try_module_get(watcher->me)) {		up(&ebt_mutex);		return -ENOENT;	}	up(&ebt_mutex);	if (watcher->check &&	   watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {		BUGPRINT("watcher->check failed\n");		module_put(watcher->me);		return -EINVAL;	}	(*cnt)++;	return 0;}/* * this one is very careful, as it is the first function * to parse the userspace data */static inline intebt_check_entry_size_and_hooks(struct ebt_entry *e,   struct ebt_table_info *newinfo, char *base, char *limit,   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks){	int i;	for (i = 0; i < NF_BR_NUMHOOKS; i++) {		if ((valid_hooks & (1 << i)) == 0)			continue;		if ( (char *)hook_entries[i] - base ==		   (char *)e - newinfo->entries)			break;	}	/* beginning of a new chain

⌨️ 快捷键说明

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