Commit 1ae26f93 authored by Bart De Schuymer's avatar Bart De Schuymer Committed by David S. Miller

[BRIDGE]: Add Ethernet bridge tables support.

parent 50fc5ecd
...@@ -531,6 +531,14 @@ M: mike@i-Connect.Net ...@@ -531,6 +531,14 @@ M: mike@i-Connect.Net
L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org L: linux-eata@i-connect.net, linux-scsi@vger.kernel.org
S: Maintained S: Maintained
EBTABLES
P: Bart De Schuymer
M: bart.de.schuymer@pandora.be
L: ebtables-user@lists.sourceforge.net
L: ebtables-devel@lists.sourceforge.net
W: http://ebtables.sourceforge.net/
S: Maintained
EEPRO100 NETWORK DRIVER EEPRO100 NETWORK DRIVER
P: Andrey V. Savochkin P: Andrey V. Savochkin
M: saw@saw.sw.com.sg M: saw@saw.sw.com.sg
......
...@@ -102,7 +102,8 @@ struct net_bridge; ...@@ -102,7 +102,8 @@ struct net_bridge;
struct net_bridge_port; struct net_bridge_port;
extern int (*br_ioctl_hook)(unsigned long arg); extern int (*br_ioctl_hook)(unsigned long arg);
extern void (*br_handle_frame_hook)(struct sk_buff *skb); extern int (*br_handle_frame_hook)(struct sk_buff *skb);
extern int (*br_should_route_hook)(struct sk_buff **pskb);
#endif #endif
......
...@@ -18,7 +18,18 @@ ...@@ -18,7 +18,18 @@
#define NF_BR_LOCAL_OUT 3 #define NF_BR_LOCAL_OUT 3
/* Packets about to hit the wire. */ /* Packets about to hit the wire. */
#define NF_BR_POST_ROUTING 4 #define NF_BR_POST_ROUTING 4
#define NF_BR_NUMHOOKS 5 /* Not really a hook, but used for the ebtables broute table */
#define NF_BR_BROUTING 5
#define NF_BR_NUMHOOKS 6
enum nf_br_hook_priorities {
NF_BR_PRI_FIRST = INT_MIN,
NF_BR_PRI_FILTER_BRIDGED = -200,
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 = 300,
NF_BR_PRI_LAST = INT_MAX,
};
#endif #endif
...@@ -65,6 +65,9 @@ if [ "$CONFIG_DECNET" != "n" ]; then ...@@ -65,6 +65,9 @@ if [ "$CONFIG_DECNET" != "n" ]; then
source net/decnet/Config.in source net/decnet/Config.in
fi fi
dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
source net/bridge/netfilter/Config.in
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
......
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
# Makefile for the IEEE 802.1d ethernet bridging layer. # Makefile for the IEEE 802.1d ethernet bridging layer.
# #
export-objs := br.o
obj-$(CONFIG_BRIDGE) += bridge.o obj-$(CONFIG_BRIDGE) += bridge.o
bridge-objs := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ bridge-objs := 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 \ br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
br_stp_if.o br_stp_timer.o br_stp_if.o br_stp_timer.o
obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "../atm/lec.h" #include "../atm/lec.h"
#endif #endif
int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
void br_dec_use_count() void br_dec_use_count()
{ {
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
...@@ -74,6 +76,8 @@ static void __exit br_deinit(void) ...@@ -74,6 +76,8 @@ static void __exit br_deinit(void)
#endif #endif
} }
EXPORT_SYMBOL(br_should_route_hook);
module_init(br_init) module_init(br_init)
module_exit(br_deinit) module_exit(br_deinit)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -49,6 +49,9 @@ static int __br_forward_finish(struct sk_buff *skb) ...@@ -49,6 +49,9 @@ static int __br_forward_finish(struct sk_buff *skb)
static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb) static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
{ {
skb->dev = to->dev; skb->dev = to->dev;
#ifdef CONFIG_NETFILTER_DEBUG
skb->nf_debug = 0;
#endif
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
__br_forward_finish); __br_forward_finish);
} }
......
...@@ -24,6 +24,9 @@ unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; ...@@ -24,6 +24,9 @@ unsigned char bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
static int br_pass_frame_up_finish(struct sk_buff *skb) static int br_pass_frame_up_finish(struct sk_buff *skb)
{ {
#ifdef CONFIG_NETFILTER_DEBUG
skb->nf_debug = 0;
#endif
netif_rx(skb); netif_rx(skb);
return 0; return 0;
...@@ -112,7 +115,7 @@ static int br_handle_frame_finish(struct sk_buff *skb) ...@@ -112,7 +115,7 @@ static int br_handle_frame_finish(struct sk_buff *skb)
return 0; return 0;
} }
void br_handle_frame(struct sk_buff *skb) int br_handle_frame(struct sk_buff *skb)
{ {
struct net_bridge *br; struct net_bridge *br;
unsigned char *dest; unsigned char *dest;
...@@ -146,25 +149,29 @@ void br_handle_frame(struct sk_buff *skb) ...@@ -146,25 +149,29 @@ void br_handle_frame(struct sk_buff *skb)
goto handle_special_frame; goto handle_special_frame;
if (p->state == BR_STATE_FORWARDING) { if (p->state == BR_STATE_FORWARDING) {
if (br_should_route_hook && br_should_route_hook(&skb))
return -1;
NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL, NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish); br_handle_frame_finish);
read_unlock(&br->lock); read_unlock(&br->lock);
return; return 0;
} }
err: err:
read_unlock(&br->lock); read_unlock(&br->lock);
err_nolock: err_nolock:
kfree_skb(skb); kfree_skb(skb);
return; return 0;
handle_special_frame: handle_special_frame:
if (!dest[5]) { if (!dest[5]) {
br_stp_handle_bpdu(skb); br_stp_handle_bpdu(skb);
read_unlock(&br->lock); read_unlock(&br->lock);
return; return 0;
} }
kfree_skb(skb); kfree_skb(skb);
read_unlock(&br->lock); read_unlock(&br->lock);
return 0;
} }
...@@ -166,7 +166,7 @@ extern void br_get_port_ifindices(struct net_bridge *br, ...@@ -166,7 +166,7 @@ extern void br_get_port_ifindices(struct net_bridge *br,
int *ifindices); int *ifindices);
/* br_input.c */ /* br_input.c */
extern void br_handle_frame(struct sk_buff *skb); extern int br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */ /* br_ioctl.c */
extern void br_call_ioctl_atomic(void (*fn)(void)); extern void br_call_ioctl_atomic(void (*fn)(void));
......
CONFIG_BRIDGE_EBT
ebtables is an extendable frame filtering system for the Linux
Ethernet bridge. Its usage and implementation is very similar to that
of iptables.
The difference is that ebtables works on the Link Layer, while iptables
works on the Network Layer. ebtables can filter all frames that come
into contact with a logical bridge device.
Apart from filtering, ebtables also allows MAC source and destination
alterations (we call it MAC SNAT and MAC DNAT) and also provides
functionality for making Linux a brouter.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_T_FILTER
The ebtables filter table is used to define frame filtering rules at
local input, forwarding and local output. See the man page for
ebtables(8).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_T_NAT
The ebtables nat table is used to define rules that alter the MAC
source address (MAC SNAT) or the MAC destination address (MAC DNAT).
See the man page for ebtables(8).
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_BROUTE
The ebtables broute table is used to define rules that decide between
bridging and routing frames, giving Linux the functionality of a
brouter. See the man page for ebtables(8) and examples on the ebtables
website.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_LOG
This option adds the log target, that you can use in any rule in
any ebtables table. It records the frame header to the syslog.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_IPF
This option adds the IP match, which allows basic IP header field
filtering.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_ARPF
This option adds the ARP match, which allows ARP and RARP header field
filtering.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_VLANF
This option adds the 802.1Q vlan match, which allows the filtering of
802.1Q vlan fields.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_MARKF
This option adds the mark match, which allows matching frames based on
the 'nfmark' value in the frame. This can be set by the mark target.
This value is the same as the one used in the iptables mark match and
target.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_SNAT
This option adds the MAC SNAT target, which allows altering the MAC
source address of frames.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_DNAT
This option adds the MAC DNAT target, which allows altering the MAC
destination address of frames.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_REDIRECT
This option adds the MAC redirect target, which allows altering the MAC
destination address of a frame to that of the device it arrived on.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
CONFIG_BRIDGE_EBT_MARK_T
This option adds the mark target, which allows marking frames by
setting the 'nfmark' value in the frame.
This value is the same as the one used in the iptables mark match and
target.
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
#
# Bridge netfilter configuration
#
dep_tristate ' Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
dep_tristate ' ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
dep_tristate ' ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
#
# Makefile for the netfilter modules for Link Layer filtering on a bridge.
#
export-objs := 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
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
/*
* ebt_arp
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
* Tim Gardner <timg@tpi.com>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_arp.h>
#include <linux/if_arp.h>
#include <linux/module.h>
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");
/*
* ebt_dnat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* June, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
#include <net/sock.h>
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");
/*
* ebt_ip
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_ip.h>
#include <linux/ip.h>
#include <linux/module.h>
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");
/*
* ebt_log
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_log.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/if_arp.h>
#include <linux/spinlock.h>
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");
/*
* ebt_mark
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* 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 <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_mark_t.h>
#include <linux/module.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 *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");
/*
* ebt_mark_m
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* July, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_mark_m.h>
#include <linux/module.h>
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");
/*
* ebt_redirect
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_redirect.h>
#include <linux/module.h>
#include <net/sock.h>
#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");
/*
* ebt_snat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* June, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/module.h>
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");
This diff is collapsed.
/*
* ebtable_broute
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* 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 <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#include <linux/if_bridge.h>
#include <linux/brlock.h>
// 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");
/*
* ebtable_filter
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#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");
/*
* ebtable_nat
*
* Authors:
* Bart De Schuymer <bart.de.schuymer@pandora.be>
*
* April, 2002
*
*/
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/module.h>
#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");
This diff is collapsed.
...@@ -1397,7 +1397,7 @@ void net_call_rx_atomic(void (*fn)(void)) ...@@ -1397,7 +1397,7 @@ void net_call_rx_atomic(void (*fn)(void))
} }
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
#endif #endif
static __inline__ int handle_bridge(struct sk_buff *skb, static __inline__ int handle_bridge(struct sk_buff *skb,
...@@ -1414,7 +1414,6 @@ static __inline__ int handle_bridge(struct sk_buff *skb, ...@@ -1414,7 +1414,6 @@ static __inline__ int handle_bridge(struct sk_buff *skb,
} }
} }
br_handle_frame_hook(skb);
return ret; return ret;
} }
...@@ -1475,7 +1474,12 @@ int netif_receive_skb(struct sk_buff *skb) ...@@ -1475,7 +1474,12 @@ int netif_receive_skb(struct sk_buff *skb)
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if (skb->dev->br_port && br_handle_frame_hook) { if (skb->dev->br_port && br_handle_frame_hook) {
return handle_bridge(skb, pt_prev); int ret;
ret = handle_bridge(skb, pt_prev);
if (br_handle_frame_hook(skb) == 0)
return ret;
pt_prev = NULL;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment