From e5ed21681d65767a0bfdbb30e92d6c40fdca8ea6 Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Mon, 16 Sep 2002 20:02:51 +0000 Subject: *** empty log message *** --- kernel/linux2.5/net/bridge/netfilter/Makefile | 2 +- kernel/linux2.5/net/bridge/netfilter/ebt_arp.c | 101 +++++++ kernel/linux2.5/net/bridge/netfilter/ebt_dnat.c | 64 +++++ kernel/linux2.5/net/bridge/netfilter/ebt_ip.c | 72 +++++ kernel/linux2.5/net/bridge/netfilter/ebt_log.c | 99 +++++++ kernel/linux2.5/net/bridge/netfilter/ebt_mark.c | 65 +++++ kernel/linux2.5/net/bridge/netfilter/ebt_mark_m.c | 60 ++++ .../linux2.5/net/bridge/netfilter/ebt_redirect.c | 70 +++++ kernel/linux2.5/net/bridge/netfilter/ebt_snat.c | 63 ++++ kernel/linux2.5/net/bridge/netfilter/ebt_vlan.c | 316 +++++++++++++++++++++ .../linux2.5/net/bridge/netfilter/ebtable_broute.c | 78 +++++ .../linux2.5/net/bridge/netfilter/ebtable_filter.c | 89 ++++++ kernel/linux2.5/net/bridge/netfilter/ebtable_nat.c | 95 +++++++ 13 files changed, 1173 insertions(+), 1 deletion(-) create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_arp.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_dnat.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_ip.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_log.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_mark.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_mark_m.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_redirect.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_snat.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebt_vlan.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebtable_broute.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebtable_filter.c create mode 100644 kernel/linux2.5/net/bridge/netfilter/ebtable_nat.c diff --git a/kernel/linux2.5/net/bridge/netfilter/Makefile b/kernel/linux2.5/net/bridge/netfilter/Makefile index a6e4bec..51be8f5 100644 --- a/kernel/linux2.5/net/bridge/netfilter/Makefile +++ b/kernel/linux2.5/net/bridge/netfilter/Makefile @@ -4,7 +4,7 @@ export-objs := ebtables.o -obj-$(CONFIG_BRIDGE_EBT) += ebtables.o +obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_arp.c b/kernel/linux2.5/net/bridge/netfilter/ebt_arp.c new file mode 100644 index 0000000..22bad10 --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_arp.c @@ -0,0 +1,101 @@ +/* + * ebt_arp + * + * Authors: + * Bart De Schuymer + * Tim Gardner + * + * April, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, unsigned int datalen) +{ + struct ebt_arp_info *info = (struct ebt_arp_info *)data; + + if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != + ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE)) + return EBT_NOMATCH; + if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != + ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE)) + return EBT_NOMATCH; + if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != + ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE)) + return EBT_NOMATCH; + + if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) + { + uint32_t arp_len = sizeof(struct arphdr) + + (2 * (((*skb).nh.arph)->ar_hln)) + + (2 * (((*skb).nh.arph)->ar_pln)); + uint32_t dst; + uint32_t src; + + // Make sure the packet is long enough. + if ((((*skb).nh.raw) + arp_len) > (*skb).tail) + return EBT_NOMATCH; + // IPv4 addresses are always 4 bytes. + if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t)) + return EBT_NOMATCH; + + if (info->bitmask & EBT_ARP_SRC_IP) { + memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) + + ((*skb).nh.arph)->ar_hln, sizeof(uint32_t)); + if (FWINV(info->saddr != (src & info->smsk), + EBT_ARP_SRC_IP)) + return EBT_NOMATCH; + } + + if (info->bitmask & EBT_ARP_DST_IP) { + memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) + + (2*(((*skb).nh.arph)->ar_hln)) + + (((*skb).nh.arph)->ar_pln), sizeof(uint32_t)); + if (FWINV(info->daddr != (dst & info->dmsk), + EBT_ARP_DST_IP)) + return EBT_NOMATCH; + } + } + return EBT_MATCH; +} + +static int ebt_arp_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_arp_info *info = (struct ebt_arp_info *)data; + + if (datalen != sizeof(struct ebt_arp_info)) + return -EINVAL; + if ((e->ethproto != __constant_htons(ETH_P_ARP) && + e->ethproto != __constant_htons(ETH_P_RARP)) || + e->invflags & EBT_IPROTO) + return -EINVAL; + if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_arp = +{ + {NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_arp); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_arp); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_dnat.c b/kernel/linux2.5/net/bridge/netfilter/ebt_dnat.c new file mode 100644 index 0000000..8247e1d --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_dnat.c @@ -0,0 +1,64 @@ +/* + * ebt_dnat + * + * Authors: + * Bart De Schuymer + * + * June, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_target_dnat(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_nat_info *info = (struct ebt_nat_info *)data; + + memcpy(((**pskb).mac.ethernet)->h_dest, info->mac, + ETH_ALEN * sizeof(unsigned char)); + return info->target; +} + +static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *)data; + + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if ( (strcmp(tablename, "nat") || + (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && + (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) + return -EINVAL; + if (datalen != sizeof(struct ebt_nat_info)) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target dnat = +{ + {NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&dnat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&dnat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_ip.c b/kernel/linux2.5/net/bridge/netfilter/ebt_ip.c new file mode 100644 index 0000000..5339c11 --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_ip.c @@ -0,0 +1,72 @@ +/* + * ebt_ip + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include + +static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, + unsigned int datalen) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)data; + + if (info->bitmask & EBT_IP_TOS && + FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS)) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP_PROTO && FWINV(info->protocol != + ((*skb).nh.iph)->protocol, EBT_IP_PROTO)) + return EBT_NOMATCH; + if (info->bitmask & EBT_IP_SOURCE && + FWINV((((*skb).nh.iph)->saddr & info->smsk) != + info->saddr, EBT_IP_SOURCE)) + return EBT_NOMATCH; + if ((info->bitmask & EBT_IP_DEST) && + FWINV((((*skb).nh.iph)->daddr & info->dmsk) != + info->daddr, EBT_IP_DEST)) + return EBT_NOMATCH; + return EBT_MATCH; +} + +static int ebt_ip_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_ip_info *info = (struct ebt_ip_info *)data; + + if (datalen != sizeof(struct ebt_ip_info)) + return -EINVAL; + if (e->ethproto != __constant_htons(ETH_P_IP) || + e->invflags & EBT_IPROTO) + return -EINVAL; + if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) + return -EINVAL; + return 0; +} + +static struct ebt_match filter_ip = +{ + {NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_match(&filter_ip); +} + +static void __exit fini(void) +{ + ebt_unregister_match(&filter_ip); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_log.c b/kernel/linux2.5/net/bridge/netfilter/ebt_log.c new file mode 100644 index 0000000..cdd177f --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_log.c @@ -0,0 +1,99 @@ +/* + * ebt_log + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include +#include +#include + +static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED; + +static int ebt_log_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_log_info *info = (struct ebt_log_info *)data; + + if (datalen != sizeof(struct ebt_log_info)) + return -EINVAL; + if (info->bitmask & ~EBT_LOG_MASK) + return -EINVAL; + if (info->loglevel >= 8) + return -EINVAL; + info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; + return 0; +} + +static void ebt_log(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *data, unsigned int datalen) +{ + struct ebt_log_info *info = (struct ebt_log_info *)data; + char level_string[4] = "< >"; + level_string[1] = '0' + info->loglevel; + + spin_lock_bh(&ebt_log_lock); + printk(level_string); + printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "", + out ? out->name : ""); + + if (skb->dev->hard_header_len) { + int i; + unsigned char *p = (skb->mac.ethernet)->h_source; + + printk("MAC source = "); + for (i = 0; i < ETH_ALEN; i++,p++) + printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); + printk("MAC dest = "); + p = (skb->mac.ethernet)->h_dest; + for (i = 0; i < ETH_ALEN; i++,p++) + printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':'); + } + printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto)); + + if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto == + htons(ETH_P_IP)){ + struct iphdr *iph = skb->nh.iph; + printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol); + } + + if ((info->bitmask & EBT_LOG_ARP) && + ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) || + (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) { + struct arphdr * arph = skb->nh.arph; + printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d", + ntohs(arph->ar_hrd), ntohs(arph->ar_pro), + ntohs(arph->ar_op)); + } + printk("\n"); + spin_unlock_bh(&ebt_log_lock); +} + +struct ebt_watcher log = +{ + {NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_watcher(&log); +} + +static void __exit fini(void) +{ + ebt_unregister_watcher(&log); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_mark.c b/kernel/linux2.5/net/bridge/netfilter/ebt_mark.c new file mode 100644 index 0000000..4a42a75 --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_mark.c @@ -0,0 +1,65 @@ +/* + * ebt_mark + * + * 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 + +#include +#include +#include + +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 *info = (struct ebt_mark_t_info *)data; + + if ((*pskb)->nfmark != info->mark) { + (*pskb)->nfmark = info->mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return info->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 *info = (struct ebt_mark_t_info *)data; + + if (datalen != sizeof(struct ebt_mark_t_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if (INVALID_TARGET) + 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); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_mark_m.c b/kernel/linux2.5/net/bridge/netfilter/ebt_mark_m.c new file mode 100644 index 0000000..f3d290b --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_mark_m.c @@ -0,0 +1,60 @@ +/* + * 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) +{ + 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 (datalen != sizeof(struct ebt_mark_m_info)) + return -EINVAL; + 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; + 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); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_redirect.c b/kernel/linux2.5/net/bridge/netfilter/ebt_redirect.c new file mode 100644 index 0000000..c8ed4cb --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_redirect.c @@ -0,0 +1,70 @@ +/* + * ebt_redirect + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#include +#include +#include "../br_private.h" + +static int ebt_target_redirect(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_redirect_info *info = (struct ebt_redirect_info *)data; + + if (hooknr != NF_BR_BROUTING) + memcpy((**pskb).mac.ethernet->h_dest, + in->br_port->br->dev.dev_addr, ETH_ALEN); + else { + memcpy((**pskb).mac.ethernet->h_dest, + in->dev_addr, ETH_ALEN); + (*pskb)->pkt_type = PACKET_HOST; + } + return info->target; +} + +static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; + + if (datalen != sizeof(struct ebt_redirect_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && + (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target redirect_target = +{ + {NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect, + ebt_target_redirect_check, NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&redirect_target); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&redirect_target); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_snat.c b/kernel/linux2.5/net/bridge/netfilter/ebt_snat.c new file mode 100644 index 0000000..0e26f6c --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_snat.c @@ -0,0 +1,63 @@ +/* + * ebt_snat + * + * Authors: + * Bart De Schuymer + * + * June, 2002 + * + */ + +#include +#include +#include + +static int ebt_target_snat(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_nat_info *info = (struct ebt_nat_info *) data; + + memcpy(((**pskb).mac.ethernet)->h_source, info->mac, + ETH_ALEN * sizeof(unsigned char)); + return info->target; +} + +static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, + const struct ebt_entry *e, void *data, unsigned int datalen) +{ + struct ebt_nat_info *info = (struct ebt_nat_info *) data; + + if (datalen != sizeof(struct ebt_nat_info)) + return -EINVAL; + if (BASE_CHAIN && info->target == EBT_RETURN) + return -EINVAL; + CLEAR_BASE_CHAIN_BIT; + if (strcmp(tablename, "nat")) + return -EINVAL; + if (hookmask & ~(1 << NF_BR_POST_ROUTING)) + return -EINVAL; + if (INVALID_TARGET) + return -EINVAL; + return 0; +} + +static struct ebt_target snat = +{ + {NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check, + NULL, THIS_MODULE +}; + +static int __init init(void) +{ + return ebt_register_target(&snat); +} + +static void __exit fini(void) +{ + ebt_unregister_target(&snat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebt_vlan.c b/kernel/linux2.5/net/bridge/netfilter/ebt_vlan.c new file mode 100644 index 0000000..6f8915f --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebt_vlan.c @@ -0,0 +1,316 @@ +/* + * Description: EBTables 802.1Q match extension kernelspace module. + * Authors: Nick Fedchik + * Bart De Schuymer + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +static unsigned char debug; +#define MODULE_VERSION "0.4 (" __DATE__ " " __TIME__ ")" + +MODULE_PARM (debug, "0-1b"); +MODULE_PARM_DESC (debug, "debug=1 is turn on debug messages"); +MODULE_AUTHOR ("Nick Fedchik "); +MODULE_DESCRIPTION ("802.1Q match module (ebtables extension), v" + MODULE_VERSION); +MODULE_LICENSE ("GPL"); + + +#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG __FILE__ ":" __VA_ARGS__) +#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" +#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ +#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ +#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1; + +/* + * Function description: ebt_filter_vlan() is main engine for + * checking passed 802.1Q frame according to + * the passed extension parameters (in the *data buffer) + * ebt_filter_vlan() is called after successfull check the rule params + * by ebt_check_vlan() function. + * Parameters: + * const struct sk_buff *skb - pointer to passed ethernet frame buffer + * const void *data - pointer to passed extension parameters + * unsigned int datalen - length of passed *data buffer + * const struct net_device *in - + * const struct net_device *out - + * const struct ebt_counter *c - + * Returned values: + * 0 - ok (all rule params matched) + * 1 - miss (rule params not acceptable to the parsed frame) + */ +static int +ebt_filter_vlan (const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *data, + unsigned int datalen) +{ + struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* userspace data */ + struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw; /* Passed tagged frame */ + + unsigned short TCI; /* Whole TCI, given from parsed frame */ + unsigned short id; /* VLAN ID, given from frame TCI */ + unsigned char prio; /* user_priority, given from frame TCI */ + unsigned short encap; /* VLAN encapsulated Type/Length field, given from orig frame */ + + /* + * Tag Control Information (TCI) consists of the following elements: + * - User_priority. This field allows the tagged frame to carry user_priority + * information across Bridged LANs in which individual LAN segments may be unable to signal + * priority information (e.g., 802.3/Ethernet segments). + * The user_priority field is three bits in length, + * interpreted as a binary number. The user_priority is therefore + * capable of representing eight priority levels, 0 through 7. + * The use and interpretation of this field is defined in ISO/IEC 15802-3. + * - Canonical Format Indicator (CFI). This field is used, + * in 802.3/Ethernet, to signal the presence or absence + * of a RIF field, and, in combination with the Non-canonical Format Indicator (NCFI) carried + * in the RIF, to signal the bit order of address information carried in the encapsulated + * frame. The Canonical Format Indicator (CFI) is a single bit flag value. + * - VLAN Identifier (VID). This field uniquely identifies the VLAN to + * which the frame belongs. The twelve-bit VLAN Identifier (VID) field + * uniquely identify the VLAN to which the frame belongs. + * The VID is encoded as an unsigned binary number. + */ + TCI = ntohs (frame->h_vlan_TCI); + id = TCI & 0xFFF; + prio = TCI >> 13; + encap = frame->h_vlan_encapsulated_proto; + + /* + * First step is to check is null VLAN ID present + * in the parsed frame + */ + if (!(id)) { + /* + * Checking VLAN Identifier (VID) + */ + if (GET_BITMASK (EBT_VLAN_ID)) { /* Is VLAN ID parsed? */ + EXIT_ON_MISMATCH (id, EBT_VLAN_ID); + DEBUG_MSG + ("matched rule id=%s%d for frame id=%d\n", + INV_FLAG (EBT_VLAN_ID), info->id, id); + } + } else { + /* + * Checking user_priority + */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { /* Is VLAN user_priority parsed? */ + EXIT_ON_MISMATCH (prio, EBT_VLAN_PRIO); + DEBUG_MSG + ("matched rule prio=%s%d for frame prio=%d\n", + INV_FLAG (EBT_VLAN_PRIO), info->prio, + prio); + } + } + /* + * Checking Encapsulated Proto (Length/Type) field + */ + if (GET_BITMASK (EBT_VLAN_ENCAP)) { /* Is VLAN Encap parsed? */ + EXIT_ON_MISMATCH (encap, EBT_VLAN_ENCAP); + DEBUG_MSG ("matched encap=%s%2.4X for frame encap=%2.4X\n", + INV_FLAG (EBT_VLAN_ENCAP), + ntohs (info->encap), ntohs (encap)); + } + /* + * All possible extension parameters was parsed. + * If rule never returned by missmatch, then all ok. + */ + return 0; +} + +/* + * Function description: ebt_vlan_check() is called when userspace + * delivers the table to the kernel, + * and to check that userspace doesn't give a bad table. + * Parameters: + * const char *tablename - table name string + * unsigned int hooknr - hook number + * const struct ebt_entry *e - ebtables entry basic set + * const void *data - pointer to passed extension parameters + * unsigned int datalen - length of passed *data buffer + * Returned values: + * 0 - ok (all delivered rule params are correct) + * 1 - miss (rule params is out of range, invalid, incompatible, etc.) + */ +static int +ebt_check_vlan (const char *tablename, + unsigned int hooknr, + const struct ebt_entry *e, void *data, + unsigned int datalen) +{ + struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; + + /* + * Parameters buffer overflow check + */ + if (datalen != sizeof (struct ebt_vlan_info)) { + DEBUG_MSG + ("params size %d is not eq to ebt_vlan_info (%d)\n", + datalen, sizeof (struct ebt_vlan_info)); + return -EINVAL; + } + + /* + * Is it 802.1Q frame checked? + */ + if (e->ethproto != __constant_htons (ETH_P_8021Q)) { + DEBUG_MSG ("passed entry proto %2.4X is not 802.1Q (8100)\n", + (unsigned short) ntohs (e->ethproto)); + return -EINVAL; + } + + /* + * Check for bitmask range + * True if even one bit is out of mask + */ + if (info->bitmask & ~EBT_VLAN_MASK) { + DEBUG_MSG ("bitmask %2X is out of mask (%2X)\n", + info->bitmask, EBT_VLAN_MASK); + return -EINVAL; + } + + /* + * Check for inversion flags range + */ + if (info->invflags & ~EBT_VLAN_MASK) { + DEBUG_MSG ("inversion flags %2X is out of mask (%2X)\n", + info->invflags, EBT_VLAN_MASK); + return -EINVAL; + } + + /* + * Reserved VLAN ID (VID) values + * ----------------------------- + * 0 - The null VLAN ID. Indicates that the tag header contains only user_priority information; + * no VLAN identifier is present in the frame. This VID value shall not be + * configured as a PVID, configured in any Filtering Database entry, or used in any + * Management operation. + * + * 1 - The default Port VID (PVID) value used for classifying frames on ingress through a Bridge + * Port. The PVID value can be changed by management on a per-Port basis. + * + * 0x0FFF - Reserved for implementation use. This VID value shall not be configured as a + * PVID or transmitted in a tag header. + * + * The remaining values of VID are available for general use as VLAN identifiers. + * A Bridge may implement the ability to support less than the full range of VID values; + * i.e., for a given implementation, + * an upper limit, N, is defined for the VID values supported, where N is less than or equal to 4094. + * All implementations shall support the use of all VID values in the range 0 through their defined maximum + * VID, N. + * + * For Linux, N = 4094. + */ + if (GET_BITMASK (EBT_VLAN_ID)) { /* when vlan-id param was spec-ed */ + if (!!info->id) { /* if id!=0 => check vid range */ + if (info->id > 4094) { /* check if id > than (0x0FFE) */ + DEBUG_MSG + ("vlan id %d is out of range (1-4094)\n", + info->id); + return -EINVAL; + } + /* + * Note: This is valid VLAN-tagged frame point. + * Any value of user_priority are acceptable, but could be ignored + * according to 802.1Q Std. + */ + } else { + /* + * if id=0 (null VLAN ID) => Check for user_priority range + */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { + if ((unsigned char) info->prio > 7) { + DEBUG_MSG + ("prio %d is out of range (0-7)\n", + info->prio); + return -EINVAL; + } + } + /* + * Note2: This is valid priority-tagged frame point + * with null VID field. + */ + } + } else { /* VLAN Id not set */ + if (GET_BITMASK (EBT_VLAN_PRIO)) { /* But user_priority is set - abnormal! */ + info->id = 0; /* Set null VID (case for Priority-tagged frames) */ + SET_BITMASK (EBT_VLAN_ID); /* and set id flag */ + } + } + /* + * Check for encapsulated proto range - it is possible to be any value for u_short range. + * When relaying a tagged frame between 802.3/Ethernet MACs, + * a Bridge may adjust the padding field such that + * the minimum size of a transmitted tagged frame is 68 octets (7.2). + * if_ether.h: ETH_ZLEN 60 - Min. octets in frame sans FCS + */ + if (GET_BITMASK (EBT_VLAN_ENCAP)) { + if ((unsigned short) ntohs (info->encap) < ETH_ZLEN) { + DEBUG_MSG + ("encap packet length %d is less than minimal %d\n", + ntohs (info->encap), ETH_ZLEN); + return -EINVAL; + } + } + + /* + * Otherwise is all correct + */ + DEBUG_MSG ("802.1Q tagged frame checked (%s table, %d hook)\n", + tablename, hooknr); + return 0; +} + +static struct ebt_match filter_vlan = { + {NULL, NULL}, + EBT_VLAN_MATCH, + ebt_filter_vlan, + ebt_check_vlan, + NULL, + THIS_MODULE +}; + +/* + * Module initialization function. + * Called when module is loaded to kernelspace + */ +static int __init init (void) +{ + DEBUG_MSG ("ebtables 802.1Q extension module v" + MODULE_VERSION "\n"); + DEBUG_MSG ("module debug=%d\n", !!debug); + return ebt_register_match (&filter_vlan); +} + +/* + * Module "finalization" function + * Called when download module from kernelspace + */ +static void __exit fini (void) +{ + ebt_unregister_match (&filter_vlan); +} + +module_init (init); +module_exit (fini); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebtable_broute.c b/kernel/linux2.5/net/bridge/netfilter/ebtable_broute.c new file mode 100644 index 0000000..c7ec771 --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebtable_broute.c @@ -0,0 +1,78 @@ +/* + * ebtable_broute + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + * This table lets you choose between routing and bridging for frames + * entering on a bridge enslaved nic. This table is traversed before any + * other ebtables table. See net/bridge/br_input.c. + */ + +#include +#include +#include +#include + +// EBT_ACCEPT means the frame will be bridged +// EBT_DROP means the frame will be routed +static struct ebt_entries initial_chain = + {0, "BROUTING", 0, EBT_ACCEPT, 0}; + +static struct ebt_replace initial_table = +{ + "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries), + { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~(1 << NF_BR_BROUTING)) + return -EINVAL; + return 0; +} + +static struct ebt_table broute_table = +{ + {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING, + RW_LOCK_UNLOCKED, check, NULL +}; + +static int ebt_broute(struct sk_buff **pskb) +{ + int ret; + + ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL, + &broute_table); + if (ret == NF_DROP) + return 1; // route it + return 0; // bridge it +} + +static int __init init(void) +{ + int ret; + + ret = ebt_register_table(&broute_table); + if (ret < 0) + return ret; + br_write_lock_bh(BR_NETPROTO_LOCK); + // see br_input.c + br_should_route_hook = ebt_broute; + br_write_unlock_bh(BR_NETPROTO_LOCK); + return ret; +} + +static void __exit fini(void) +{ + br_write_lock_bh(BR_NETPROTO_LOCK); + br_should_route_hook = NULL; + br_write_unlock_bh(BR_NETPROTO_LOCK); + ebt_unregister_table(&broute_table); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebtable_filter.c b/kernel/linux2.5/net/bridge/netfilter/ebtable_filter.c new file mode 100644 index 0000000..d58c2a4 --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebtable_filter.c @@ -0,0 +1,89 @@ +/* + * ebtable_filter + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include + +#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \ + (1 << NF_BR_LOCAL_OUT)) + +static struct ebt_entries initial_chains[] = +{ + {0, "INPUT", 0, EBT_ACCEPT, 0}, + {0, "FORWARD", 0, EBT_ACCEPT, 0}, + {0, "OUTPUT", 0, EBT_ACCEPT, 0} +}; + +static struct ebt_replace initial_table = +{ + "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), + { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1], + [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~FILTER_VALID_HOOKS) + return -EINVAL; + return 0; +} + +static struct ebt_table frame_filter = +{ + {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, + RW_LOCK_UNLOCKED, check, NULL +}; + +static unsigned int +ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in, + const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_filter); +} + +static struct nf_hook_ops ebt_ops_filter[] = { + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN, + NF_BR_PRI_FILTER_BRIDGED}, + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD, + NF_BR_PRI_FILTER_BRIDGED}, + { { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT, + NF_BR_PRI_FILTER_OTHER} +}; + +static int __init init(void) +{ + int i, j, ret; + + ret = ebt_register_table(&frame_filter); + if (ret < 0) + return ret; + for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) + if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0) + goto cleanup; + return ret; +cleanup: + for (j = 0; j < i; j++) + nf_unregister_hook(&ebt_ops_filter[j]); + ebt_unregister_table(&frame_filter); + return ret; +} + +static void __exit fini(void) +{ + int i; + + for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++) + nf_unregister_hook(&ebt_ops_filter[i]); + ebt_unregister_table(&frame_filter); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff --git a/kernel/linux2.5/net/bridge/netfilter/ebtable_nat.c b/kernel/linux2.5/net/bridge/netfilter/ebtable_nat.c new file mode 100644 index 0000000..74602fe --- /dev/null +++ b/kernel/linux2.5/net/bridge/netfilter/ebtable_nat.c @@ -0,0 +1,95 @@ +/* + * ebtable_nat + * + * Authors: + * Bart De Schuymer + * + * April, 2002 + * + */ + +#include +#include +#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \ + (1 << NF_BR_POST_ROUTING)) + +static struct ebt_entries initial_chains[] = +{ + {0, "PREROUTING", 0, EBT_ACCEPT, 0}, + {0, "OUTPUT", 0, EBT_ACCEPT, 0}, + {0, "POSTROUTING", 0, EBT_ACCEPT, 0} +}; + +static struct ebt_replace initial_table = +{ + "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries), + { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1], + [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains +}; + +static int check(const struct ebt_table_info *info, unsigned int valid_hooks) +{ + if (valid_hooks & ~NAT_VALID_HOOKS) + return -EINVAL; + return 0; +} + +static struct ebt_table frame_nat = +{ + {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS, + RW_LOCK_UNLOCKED, check, NULL +}; + +static unsigned int +ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in + , const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_nat); +} + +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 *)) +{ + return ebt_do_table(hook, pskb, in, out, &frame_nat); +} + +static struct nf_hook_ops ebt_ops_nat[] = { + { { 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}, + { { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING, + NF_BR_PRI_NAT_DST_BRIDGED}, +}; + +static int __init init(void) +{ + int i, ret, j; + + ret = ebt_register_table(&frame_nat); + if (ret < 0) + return ret; + for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) + if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0) + goto cleanup; + return ret; +cleanup: + for (j = 0; j < i; j++) + nf_unregister_hook(&ebt_ops_nat[j]); + ebt_unregister_table(&frame_nat); + return ret; +} + +static void __exit fini(void) +{ + int i; + + for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++) + nf_unregister_hook(&ebt_ops_nat[i]); + ebt_unregister_table(&frame_nat); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); -- cgit v1.2.3