--- linux/net/core/dev.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/core/dev.c Wed Jul 31 19:04:30 2002 @@ -1385,13 +1385,6 @@ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; -#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \ - defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE) -unsigned int (*broute_decision) (unsigned int hook, struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) = NULL; -#endif #endif static __inline__ int handle_bridge(struct sk_buff *skb, --- linux/net/bridge/br.c Wed Jul 31 19:10:53 2002 +++ ebt2.0-rc1/net/bridge/br.c Wed Jul 31 19:04:30 2002 @@ -28,6 +28,14 @@ #include "../atm/lec.h" #endif +#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \ + defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE) +unsigned int (*broute_decision) (unsigned int hook, struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) = NULL; +#endif + void br_dec_use_count() { MOD_DEC_USE_COUNT; @@ -82,7 +90,12 @@ #endif } +#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \ + defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE) +EXPORT_SYMBOL(broute_decision); +#else EXPORT_NO_SYMBOLS; +#endif module_init(br_init) module_exit(br_deinit) --- linux/net/bridge/Makefile Wed Jul 31 19:10:53 2002 +++ ebt2.0-rc1/net/bridge/Makefile Wed Jul 31 19:04:30 2002 @@ -7,6 +7,12 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +ifneq ($(CONFIG_BRIDGE_EBT_BROUTE),n) +ifneq ($(CONFIG_BRIDGE_EBT_BROUTE),) +export-objs := br.o +endif +endif + O_TARGET := bridge.o obj-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \ --- linux/include/linux/netfilter_bridge.h Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/include/linux/netfilter_bridge.h Wed Jul 31 19:04:30 2002 @@ -28,8 +28,7 @@ NF_BR_PRI_FILTER_OTHER = 200, NF_BR_PRI_NAT_DST_BRIDGED = -300, NF_BR_PRI_NAT_DST_OTHER = 100, - NF_BR_PRI_NAT_SRC_BRIDGED = -100, - NF_BR_PRI_NAT_SRC_OTHER = 300, + NF_BR_PRI_NAT_SRC = 300, NF_BR_PRI_LAST = INT_MAX, }; --- linux/net/netsyms.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/netsyms.c Mon Feb 25 20:38:14 2002 @@ -228,10 +228,6 @@ #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) EXPORT_SYMBOL(br_handle_frame_hook); -#if defined(CONFIG_BRIDGE_EBT_BROUTE) || \ - defined(CONFIG_BRIDGE_EBT_BROUTE_MODULE) -EXPORT_SYMBOL(broute_decision); -#endif #ifdef CONFIG_INET EXPORT_SYMBOL(br_ioctl_hook); #endif --- linux/net/Makefile Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/Makefile Wed Jul 31 19:04:30 2002 @@ -28,7 +28,7 @@ endif ifneq ($(CONFIG_BRIDGE),n) -ifneq ($CONFIG_BRIDGE),) +ifneq ($(CONFIG_BRIDGE),) subdir-$(CONFIG_BRIDGE) += bridge/netfilter endif endif --- linux/net/bridge/netfilter/Makefile Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/Makefile Wed Jul 31 19:04:30 2002 @@ -9,7 +9,7 @@ O_TARGET := netfilter.o -export-objs = ebtables.o +export-objs := ebtables.o obj-$(CONFIG_BRIDGE_EBT) += ebtables.o obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o @@ -19,8 +19,10 @@ obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o +obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o +obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o include $(TOPDIR)/Rules.make --- linux/net/bridge/netfilter/Config.in Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/Config.in Wed Jul 31 19:04:30 2002 @@ -9,8 +9,10 @@ dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_EBT dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_EBT dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_EBT +dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_EBT dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_EBT dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_EBT dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_EBT +dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_EBT dep_tristate ' Bridge: ethernet database' CONFIG_BRIDGE_DB $CONFIG_BRIDGE --- linux/net/bridge/netfilter/ebtable_nat.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/ebtable_nat.c Wed Jul 31 19:04:30 2002 @@ -42,16 +42,6 @@ RW_LOCK_UNLOCKED, check, NULL }; -// used for snat to know if the frame comes from FORWARD or LOCAL_OUT. -// needed because of the bridge-nf patch (that allows use of iptables -// on bridged traffic) -// if the packet is routed, we want the ebtables stuff on POSTROUTING -// to be executed _after_ the iptables stuff. when it's bridged, it's -// the way around -static struct net_device __fake_net_device = { - hard_header_len: ETH_HLEN -}; - static unsigned int ebt_nat_dst (unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, @@ -60,50 +50,11 @@ return ebt_do_table(hook, pskb, in, out, &frame_nat); } -// let snat know this frame is routed -static unsigned int ebt_clear_physin (unsigned int hook, struct sk_buff **pskb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - (*pskb)->physindev = NULL; - return NF_ACCEPT; -} - -// let snat know this frame is bridged -static unsigned int ebt_set_physin (unsigned int hook, struct sk_buff **pskb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - (*pskb)->physindev = &__fake_net_device; - return NF_ACCEPT; -} - static unsigned int ebt_nat_src (unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - // this is a routed packet - if ((*pskb)->physindev == NULL) - return NF_ACCEPT; - if ((*pskb)->physindev != &__fake_net_device) - printk("ebtables (br_nat_src): physindev hack " - "doesn't work - BUG\n"); - - return ebt_do_table(hook, pskb, in, out, &frame_nat); -} - -static unsigned int ebt_nat_src_route (unsigned int hook, struct sk_buff **pskb, - const struct net_device *in, const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - // this is a bridged packet - if ((*pskb)->physindev == &__fake_net_device) - return NF_ACCEPT; - if ((*pskb)->physindev) - printk("ebtables (br_nat_src_route): physindev hack " - "doesn't work - BUG\n"); - return ebt_do_table(hook, pskb, in, out, &frame_nat); } @@ -111,15 +62,9 @@ { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT, NF_BR_PRI_NAT_DST_OTHER}, { { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING, - NF_BR_PRI_NAT_SRC_BRIDGED}, - { { NULL, NULL }, ebt_nat_src_route, PF_BRIDGE, NF_BR_POST_ROUTING, - NF_BR_PRI_NAT_SRC_OTHER}, + NF_BR_PRI_NAT_SRC}, { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING, NF_BR_PRI_NAT_DST_BRIDGED}, - { { NULL, NULL }, ebt_clear_physin, PF_BRIDGE, NF_BR_LOCAL_OUT, - NF_BR_PRI_FILTER_OTHER + 1}, - { { NULL, NULL }, ebt_set_physin, PF_BRIDGE, NF_BR_FORWARD, - NF_BR_PRI_FILTER_OTHER + 1} }; static int __init init(void) --- linux/net/bridge/netfilter/ebt_redirect.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/ebt_redirect.c Wed Jul 31 19:04:30 2002 @@ -38,6 +38,10 @@ { struct ebt_redirect_info *infostuff = (struct ebt_redirect_info *) data; + if ((hookmask & (1 << NF_BR_NUMHOOKS)) && + infostuff->target == EBT_RETURN) + return -EINVAL; + hookmask &= ~(1 << NF_BR_NUMHOOKS); if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) return -EINVAL; --- /dev/null Thu Aug 24 11:00:32 2000 +++ ebt2.0-rc1/net/bridge/netfilter/ebt_mark.c Wed Jul 31 19:04:30 2002 @@ -0,0 +1,73 @@ +/* + * ebt_mark_t + * + * Authors: + * Bart De Schuymer + * + * July, 2002 + * + */ + +// The mark target can be used in any chain +// I believe adding a mangle table just for marking is total overkill +// Marking a frame doesn't really change anything in the frame anyway +// The target member of the struct ebt_vlan_info provides the same +// functionality as a separate table + +#include +#include +#include +#include +#include +#include +#include "../br_private.h" + +static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr, + const struct net_device *in, const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_mark_t_info *infostuff = (struct ebt_mark_t_info *) data; + + if ((*pskb)->nfmark != infostuff->mark) { + (*pskb)->nfmark = infostuff->mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return infostuff->target; +} + +static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_mark_t_info *infostuff = (struct ebt_mark_t_info *) data; + + if ((hookmask & (1 << NF_BR_NUMHOOKS)) && + infostuff->target == EBT_RETURN) + return -EINVAL; + hookmask &= ~(1 << NF_BR_NUMHOOKS); + if (datalen != sizeof(struct ebt_mark_t_info)) + return -EINVAL; + if (infostuff->target < -NUM_STANDARD_TARGETS || infostuff->target >= 0) + return -EINVAL; + return 0; +} + +static struct ebt_target mark_target = +{ + {NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark, + ebt_target_mark_check, NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&mark_target); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&mark_target); +} + +module_init(init); +module_exit(fini); +EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); --- /dev/null Thu Aug 24 11:00:32 2000 +++ ebt2.0-rc1/net/bridge/netfilter/ebt_mark_m.c Wed Jul 31 19:04:30 2002 @@ -0,0 +1,62 @@ +/* + * ebt_mark_m + * + * Authors: + * Bart De Schuymer + * + * July, 2002 + * + */ + +#include +#include +#include + +static int ebt_filter_mark(const struct sk_buff *skb, + const struct net_device *in, const struct net_device *out, const void *data, + unsigned int datalen, const struct ebt_counter *c) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; + + if (info->bitmask & EBT_MARK_OR) + return !(!!(skb->nfmark & info->mask) ^ info->invert); + return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert); +} + +static int ebt_mark_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; + + if (info->bitmask & ~EBT_MARK_MASK) + return -EINVAL; + if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND)) + return -EINVAL; + if (!info->bitmask) + return -EINVAL; + if (datalen != sizeof(struct ebt_mark_m_info)) { + return -EINVAL; + } + return 0; +} + +static struct ebt_match filter_mark = +{ + {NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_mark); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_mark); +} + +module_init(init); +module_exit(fini); +EXPORT_NO_SYMBOLS; +MODULE_LICENSE("GPL"); --- linux/net/bridge/netfilter/ebt_snat.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/ebt_snat.c Wed Jul 31 19:04:30 2002 @@ -31,6 +31,10 @@ { struct ebt_nat_info *infostuff = (struct ebt_nat_info *) data; + if ((hookmask & (1 << NF_BR_NUMHOOKS)) && + infostuff->target == EBT_RETURN) + return -EINVAL; + hookmask &= ~(1 << NF_BR_NUMHOOKS); if (strcmp(tablename, "nat")) return -EINVAL; if (datalen != sizeof(struct ebt_nat_info)) --- linux/net/bridge/netfilter/ebt_dnat.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/ebt_dnat.c Wed Jul 31 19:04:30 2002 @@ -31,6 +31,10 @@ { struct ebt_nat_info *infostuff = (struct ebt_nat_info *) data; + if ((hookmask & (1 << NF_BR_NUMHOOKS)) && + infostuff->target == EBT_RETURN) + return -EINVAL; + hookmask &= ~(1 << NF_BR_NUMHOOKS); if ( (strcmp(tablename, "nat") || (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) --- linux/net/bridge/netfilter/ebtables.c Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/net/bridge/netfilter/ebtables.c Wed Jul 31 19:04:30 2002 @@ -4,7 +4,7 @@ * Author: * Bart De Schuymer * - * ebtables.c,v 2.0, April, 2002 + * 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 @@ -50,6 +50,21 @@ ": 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 void print_string(char *str); static DECLARE_MUTEX(ebt_mutex); @@ -62,10 +77,8 @@ { {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, - const struct net_device *in, - const struct net_device *out, - const struct ebt_counter *c) + const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const struct ebt_counter *c) { w->u.watcher->watcher(skb, in, out, w->data, w->watcher_size, c); @@ -74,10 +87,8 @@ } 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, - const struct ebt_counter *c) + const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const struct ebt_counter *c) { return m->u.match->match(skb, in, out, m->data, m->match_size, c); @@ -89,7 +100,51 @@ return 0; if (!device) return 1; - return strncmp(entry, device->name, IFNAMSIZ); + return !!strncmp(entry, device->name, IFNAMSIZ); +} + +#define FWINV(bool,invflg) ((bool) ^ !!(p->invflags & invflg)) +// process standard matches +static inline int ebt_basic_match(struct ebt_entry *p, struct ethhdr *h, + const struct net_device *in, const struct net_device *out) +{ + int verdict, i; + + if (p->bitmask & EBT_802_3) { + if (FWINV(ntohs(h->h_proto) >= 1536, EBT_IPROTO)) + return 1; + } else if (!(p->bitmask & EBT_NOPROTO) && + FWINV(p->ethproto != h->h_proto, EBT_IPROTO)) + return 1; + + if (FWINV(ebt_dev_check(p->in, in), EBT_IIN)) + return 1; + if (FWINV(ebt_dev_check(p->out, out), EBT_IOUT)) + return 1; + if ((!in || !in->br_port) ? 0 : FWINV(ebt_dev_check( + p->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN)) + return 1; + if ((!out || !out->br_port) ? 0 : FWINV(ebt_dev_check( + (p->logical_out), &out->br_port->br->dev), EBT_ILOGICALOUT)) + return 1; + + if (p->bitmask & EBT_SOURCEMAC) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (h->h_source[i] ^ p->sourcemac[i]) & + p->sourcemsk[i]; + if (FWINV(verdict != 0, EBT_ISOURCE) ) + return 1; + } + if (p->bitmask & EBT_DESTMAC) { + verdict = 0; + for (i = 0; i < 6; i++) + verdict |= (h->h_dest[i] ^ p->destmac[i]) & + p->destmsk[i]; + if (FWINV(verdict != 0, EBT_IDEST) ) + return 1; + } + return 0; } // Do some firewalling @@ -97,9 +152,9 @@ const struct net_device *in, const struct net_device *out, struct ebt_table *table) { - int i, j, nentries; + int i, nentries; struct ebt_entry *point; - struct ebt_counter *counter_base; + struct ebt_counter *counter_base, *cb_base; struct ebt_entry_target *t; int verdict, sp = 0; struct ebt_chainstack *cs; @@ -108,6 +163,8 @@ struct ebt_table_info *private = table->private; read_lock_bh(&table->lock); + cb_base = COUNTER_BASE(private->counters, private->nentries, \ + cpu_number_map(smp_processor_id())); if (private->chainstack) cs = private->chainstack[cpu_number_map(smp_processor_id())]; else @@ -115,117 +172,83 @@ chaininfo = private->hook_entry[hook]; nentries = private->hook_entry[hook]->nentries; point = (struct ebt_entry *)(private->hook_entry[hook]->data); - #define cb_base table->private->counters + \ - cpu_number_map(smp_processor_id()) * table->private->nentries counter_base = cb_base + private->hook_entry[hook]->counter_offset; - #define FWINV(bool,invflg) ((bool) ^ !!(point->invflags & invflg)) // base for chain jumps base = (char *)chaininfo; i = 0; - while (i < nentries) { - if ( ( point->bitmask & EBT_NOPROTO || - FWINV(point->ethproto == ((**pskb).mac.ethernet)->h_proto, - EBT_IPROTO) - || FWINV(ntohs(((**pskb).mac.ethernet)->h_proto) < 1536 && - (point->bitmask & EBT_802_3), EBT_IPROTO) ) - && FWINV(!ebt_dev_check((char *)(point->in), in), EBT_IIN) - && FWINV(!ebt_dev_check((char *)(point->out), out), EBT_IOUT) - && ((!in || !in->br_port) ? 1 : FWINV(!ebt_dev_check((char *) - (point->logical_in), &in->br_port->br->dev), EBT_ILOGICALIN)) - && ((!out || !out->br_port) ? 1 : - FWINV(!ebt_dev_check((char *) - (point->logical_out), &out->br_port->br->dev), EBT_ILOGICALOUT)) - - ) { - if (point->bitmask & EBT_SOURCEMAC) { - verdict = 0; - for (j = 0; j < 6; j++) - verdict |= (((**pskb).mac.ethernet)-> - h_source[j] ^ point->sourcemac[j]) & - point->sourcemsk[j]; - if (FWINV(!!verdict, EBT_ISOURCE) ) - goto letscontinue; - } + while (i < nentries) { + if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out)) + goto letscontinue; - if (point->bitmask & EBT_DESTMAC) { - verdict = 0; - for (j = 0; j < 6; j++) - verdict |= (((**pskb).mac.ethernet)-> - h_dest[j] ^ point->destmac[j]) & - point->destmsk[j]; - if (FWINV(!!verdict, EBT_IDEST) ) - goto letscontinue; - } + if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, + out, counter_base + i) != 0) + goto letscontinue; - if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, - out, counter_base + i) != 0) - goto letscontinue; + // increase counter + (*(counter_base + i)).pcnt++; - // increase counter - (*(counter_base + i)).pcnt++; + // these should only watch: not modify, nor tell us + // what to do with the packet + EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in, + out, counter_base + i); - // these should only watch: not modify, nor tell us - // what to do with the packet - EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in, - out, counter_base + i); - - 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) { + 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: - if (sp == 0) - // act like this is EBT_CONTINUE - goto letscontinue; - 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) + if (sp == 0) { + BUGPRINT("RETURN on base chain"); + // act like this is EBT_CONTINUE goto letscontinue; - if (verdict < 0) { - BUGPRINT("bogus standard verdict\n"); - read_unlock_bh(&table->lock); - return NF_DROP; - } - // 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); - if (chaininfo->distinguisher) { - BUGPRINT("jump to non-chain\n"); - read_unlock_bh(&table->lock); - return NF_DROP; } + sp--; + // put all the local variables right + i = cs[sp].n; + chaininfo = cs[sp].chaininfo; nentries = chaininfo->nentries; - point = (struct ebt_entry *)chaininfo->data; - counter_base = cb_base + chaininfo->counter_offset; - sp++; + point = cs[sp].e; + counter_base = cb_base + + chaininfo->counter_offset; continue; } + if (verdict == EBT_CONTINUE) + goto letscontinue; + if (verdict < 0) { + BUGPRINT("bogus standard verdict\n"); + read_unlock_bh(&table->lock); + return NF_DROP; + } + // 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); + if (chaininfo->distinguisher) { + BUGPRINT("jump to non-chain\n"); + read_unlock_bh(&table->lock); + return NF_DROP; + } + 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); @@ -284,7 +307,6 @@ request_module(modulename); ret = find_inlist_lock_noload(head, name, error, mutex); } - return ret; } #endif @@ -320,9 +342,12 @@ struct ebt_match *match; int ret; + if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) > + ((char *)e) + e->watchers_offset) + return -EINVAL; m->u.name[EBT_FUNCTION_MAXNAMELEN - 1] = '\0'; match = find_match_lock(m->u.name, &ret, &ebt_mutex); - if (!match) + if (!match) return ret; m->u.match = match; if (match->me) @@ -346,9 +371,12 @@ struct ebt_watcher *watcher; int ret; + if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) > + ((char *)e) + e->target_offset) + return -EINVAL; w->u.name[EBT_FUNCTION_MAXNAMELEN - 1] = '\0'; watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex); - if (!watcher) + if (!watcher) return ret; w->u.watcher = watcher; if (watcher->me) @@ -547,14 +575,16 @@ else break; } + // (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on + // a base chain if (i < NF_BR_NUMHOOKS) - hookmask = (1 << hook); + hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); else { for (i = 0; i < udc_cnt; i++) if ((char *)(cl_s[i].cs.chaininfo) > (char *)e) break; if (i == 0) - hookmask = (1 << hook); + hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS); else hookmask = cl_s[i - 1].hookmask; } @@ -589,9 +619,10 @@ ret = -EFAULT; goto cleanup_watchers; } - } else if (t->u.target->check && - t->u.target->check(name, hookmask, e, t->data, - t->target_size) != 0) { + } else if ((e->target_offset + t->target_size + + sizeof(struct ebt_entry_target) > e->next_offset) || + (t->u.target->check && + t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){ if (t->u.target->me) __MOD_DEC_USE_COUNT(t->u.target->me); ret = -EFAULT; @@ -611,7 +642,7 @@ { struct ebt_entry_target *t; - if (e->bitmask == 0) + if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0) return 0; // we're done if (cnt && (*cnt)-- == 0) @@ -643,7 +674,8 @@ // put back values of the time when this chain was called e = cl_s[chain_nr].cs.e; if (cl_s[chain_nr].from != -1) - nentries = cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; + nentries = + cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries; else nentries = chain->nentries; pos = cl_s[chain_nr].cs.n; @@ -679,6 +711,7 @@ BUGPRINT("loop\n"); return -1; } + // this can't be 0, so the above test is correct cl_s[i].cs.n = pos + 1; pos = 0; cl_s[i].cs.e = ((void *)e + e->next_offset); @@ -784,7 +817,7 @@ vfree(newinfo->chainstack[--i]); vfree(newinfo->chainstack); newinfo->chainstack = NULL; - break; + return -ENOMEM; } } @@ -824,7 +857,6 @@ // beginning of a chain. This can only occur in chains that // are not accessible from any base chains, so we don't care. - // we just don't trust anything repl->name[EBT_TABLE_MAXNAMELEN - 1] = '\0'; // used to know what we need to clean up if something goes wrong i = 0; @@ -841,27 +873,27 @@ } // called under write_lock -static inline void get_counters(struct ebt_counter *oldcounters, +static void get_counters(struct ebt_counter *oldcounters, struct ebt_counter *counters, unsigned int nentries) { - int i, cpu, counter_base; + int i, cpu; + struct ebt_counter *counter_base; // counters of cpu 0 memcpy(counters, oldcounters, sizeof(struct ebt_counter) * nentries); // add other counters to those of cpu 0 for (cpu = 1; cpu < smp_num_cpus; cpu++) { - counter_base = cpu * nentries; + counter_base = COUNTER_BASE(oldcounters, nentries, cpu); for (i = 0; i < nentries; i++) - counters[i].pcnt += - oldcounters[counter_base + i].pcnt; + counters[i].pcnt += counter_base[i].pcnt; } } // replace the table static int do_replace(void *user, unsigned int len) { - int ret, i; + int ret, i, countersize; struct ebt_table_info *newinfo; struct ebt_replace tmp; struct ebt_table *t; @@ -869,7 +901,7 @@ // used to be able to unlock earlier struct ebt_table_info *table; - if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) + if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) return -EFAULT; if (len != sizeof(tmp) + tmp.entries_size) { @@ -881,28 +913,19 @@ BUGPRINT("Entries_size never zero\n"); return -EINVAL; } + countersize = COUNTER_OFFSET(tmp.nentries) * smp_num_cpus; newinfo = (struct ebt_table_info *) - vmalloc(sizeof(struct ebt_table_info)); + vmalloc(sizeof(struct ebt_table_info) + countersize); if (!newinfo) return -ENOMEM; - if (tmp.nentries) { - newinfo->counters = (struct ebt_counter *)vmalloc( - sizeof(struct ebt_counter) * tmp.nentries * smp_num_cpus); - if (!newinfo->counters) { - ret = -ENOMEM; - goto free_newinfo; - } - memset(newinfo->counters, 0, - sizeof(struct ebt_counter) * tmp.nentries * smp_num_cpus); - } - else - newinfo->counters = NULL; + if (countersize) + memset(newinfo->counters, 0, countersize); newinfo->entries = (char *)vmalloc(tmp.entries_size); if (!newinfo->entries) { ret = -ENOMEM; - goto free_counters; + goto free_newinfo; } if (copy_from_user( newinfo->entries, tmp.entries, tmp.entries_size) != 0) { @@ -933,7 +956,7 @@ t = find_table_lock(tmp.name, &ret, &ebt_mutex); if (!t) - goto free_unlock; + goto free_iterate; // the table doesn't like it if (t->check && (ret = t->check(newinfo, tmp.valid_hooks))) @@ -974,8 +997,6 @@ ebt_cleanup_entry, NULL); vfree(table->entries); - if (table->counters) - vfree(table->counters); if (table->chainstack) { for (i = 0; i < smp_num_cpus; i++) vfree(table->chainstack[i]); @@ -989,6 +1010,7 @@ free_unlock: up(&ebt_mutex); +free_iterate: EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size, ebt_cleanup_entry, NULL); free_counterstmp: @@ -1003,9 +1025,6 @@ free_entries: if (newinfo->entries) vfree(newinfo->entries); -free_counters: - if (newinfo->counters) - vfree(newinfo->counters); free_newinfo: if (newinfo) vfree(newinfo); @@ -1090,7 +1109,7 @@ int ebt_register_table(struct ebt_table *table) { struct ebt_table_info *newinfo; - int ret, i; + int ret, i, countersize; if (!table || !table->table ||!table->table->entries || table->table->entries_size == 0 || @@ -1099,8 +1118,9 @@ return -EINVAL; } + countersize = COUNTER_OFFSET(table->table->nentries) * smp_num_cpus; newinfo = (struct ebt_table_info *) - vmalloc(sizeof(struct ebt_table_info)); + vmalloc(sizeof(struct ebt_table_info) + countersize); ret = -ENOMEM; if (!newinfo) return -ENOMEM; @@ -1112,24 +1132,15 @@ memcpy(newinfo->entries, table->table->entries, table->table->entries_size); - if (table->table->nentries) { - newinfo->counters = (struct ebt_counter *) - vmalloc(table->table->nentries * - sizeof(struct ebt_counter) * smp_num_cpus); - if (!newinfo->counters) - goto free_entries; - memset(newinfo->counters, 0, table->table->nentries * - sizeof(struct ebt_counter) * smp_num_cpus); - } - else - newinfo->counters = NULL; + if (countersize) + memset(newinfo->counters, 0, countersize); // fill in newinfo and parse the entries newinfo->chainstack = NULL; ret = translate_table(table->table, newinfo); if (ret != 0) { BUGPRINT("Translate_table failed\n"); - goto free_counters; + goto free_chainstack; } if (table->check && table->check(newinfo, table->valid_hooks)) { @@ -1141,7 +1152,7 @@ table->lock = RW_LOCK_UNLOCKED; ret = down_interruptible(&ebt_mutex); if (ret != 0) - goto free_counters; + goto free_chainstack; if (list_named_find(&ebt_tables, table->name)) { ret = -EEXIST; @@ -1155,15 +1166,12 @@ return 0; free_unlock: up(&ebt_mutex); -free_counters: - if (newinfo->counters) - vfree(newinfo->counters); +free_chainstack: if (newinfo->chainstack) { for (i = 0; i < smp_num_cpus; i++) vfree(newinfo->chainstack[i]); vfree(newinfo->chainstack); } -free_entries: vfree(newinfo->entries); free_newinfo: vfree(newinfo); @@ -1183,8 +1191,6 @@ up(&ebt_mutex); EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, ebt_cleanup_entry, NULL); - if (table->private->counters) - vfree(table->private->counters); if (table->private->entries) vfree(table->private->entries); if (table->private->chainstack) { @@ -1219,7 +1225,6 @@ } hlp.name[EBT_TABLE_MAXNAMELEN - 1] = '\0'; - t = find_table_lock(hlp.name, &ret, &ebt_mutex); if (!t) goto free_tmp; @@ -1344,7 +1349,7 @@ counterstmp = (struct ebt_counter *) vmalloc(nentries * sizeof(struct ebt_counter)); if (!counterstmp) { - BUGPRINT("Couldn't copy counters, out of memory\n"); + MEMPRINT("Couldn't copy counters, out of memory\n"); return -ENOMEM; } write_lock_bh(&t->lock); --- linux/include/linux/netfilter_bridge/ebtables.h Wed Jul 31 19:15:22 2002 +++ ebt2.0-rc1/include/linux/netfilter_bridge/ebtables.h Wed Jul 31 19:04:30 2002 @@ -12,9 +12,9 @@ #ifndef __LINUX_BRIDGE_EFF_H #define __LINUX_BRIDGE_EFF_H -#include // IFNAMSIZ +#include #include -#include // ETH_ALEN +#include #define EBT_TABLE_MAXNAMELEN 32 #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN @@ -46,10 +46,10 @@ }; struct ebt_entries { - // this field is always set to zero (including userspace). + // this field is always set to zero // See EBT_ENTRY_OR_ENTRIES. // Must be same size as ebt_entry.bitmask - __u32 distinguisher; + unsigned int distinguisher; // the chain name char name[EBT_CHAIN_MAXNAMELEN]; // counter offset for this chain @@ -133,27 +133,27 @@ // one entry struct ebt_entry { // this needs to be the first field - __u32 bitmask; - __u32 invflags; + unsigned int bitmask; + unsigned int invflags; __u16 ethproto; // the physical in-dev - __u8 in[IFNAMSIZ]; + char in[IFNAMSIZ]; // the logical in-dev - __u8 logical_in[IFNAMSIZ]; + char logical_in[IFNAMSIZ]; // the physical out-dev - __u8 out[IFNAMSIZ]; + char out[IFNAMSIZ]; // the logical out-dev - __u8 logical_out[IFNAMSIZ]; - __u8 sourcemac[ETH_ALEN]; - __u8 sourcemsk[ETH_ALEN]; - __u8 destmac[ETH_ALEN]; - __u8 destmsk[ETH_ALEN]; + char logical_out[IFNAMSIZ]; + unsigned char sourcemac[ETH_ALEN]; + unsigned char sourcemsk[ETH_ALEN]; + unsigned char destmac[ETH_ALEN]; + unsigned char destmsk[ETH_ALEN]; // sizeof ebt_entry + matches - __u16 watchers_offset; + unsigned int watchers_offset; // sizeof ebt_entry + matches + watchers - __u16 target_offset; + unsigned int target_offset; // sizeof ebt_entry + matches + watchers + target - __u16 next_offset; + unsigned int next_offset; unsigned char elems[0]; }; @@ -238,10 +238,10 @@ unsigned int nentries; // pointers to the start of the chains struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; - struct ebt_counter *counters; // room to maintain the stack used for jumping from and into udc struct ebt_chainstack **chainstack; char *entries; + struct ebt_counter counters[0] __attribute__((aligned(SMP_CACHE_BYTES))); }; struct ebt_table --- /dev/null Thu Aug 24 11:00:32 2000 +++ ebt2.0-rc1/include/linux/netfilter_bridge/ebt_mark_t.h Wed Jul 31 19:04:30 2002 @@ -0,0 +1,12 @@ +#ifndef __LINUX_BRIDGE_EBT_MARK_T_H +#define __LINUX_BRIDGE_EBT_MARK_T_H + +struct ebt_mark_t_info +{ + unsigned long mark; + // EBT_ACCEPT, EBT_DROP or EBT_CONTINUE or EBT_RETURN + int target; +}; +#define EBT_MARK_TARGET "mark" + +#endif --- /dev/null Thu Aug 24 11:00:32 2000 +++ ebt2.0-rc1/include/linux/netfilter_bridge/ebt_mark_m.h Wed Jul 31 19:04:30 2002 @@ -0,0 +1,15 @@ +#ifndef __LINUX_BRIDGE_EBT_MARK_M_H +#define __LINUX_BRIDGE_EBT_MARK_M_H + +#define EBT_MARK_AND 0x01 +#define EBT_MARK_OR 0x02 +#define EBT_MARK_MASK (EBT_MARK_AND | EBT_MARK_OR) +struct ebt_mark_m_info +{ + unsigned long mark, mask; + __u8 invert; + __u8 bitmask; +}; +#define EBT_MARK_MATCH "mark_m" + +#endif