summaryrefslogtreecommitdiffstats
path: root/net/bridge/netfilter
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge/netfilter')
-rw-r--r--net/bridge/netfilter/Kconfig211
-rw-r--r--net/bridge/netfilter/Makefile32
-rw-r--r--net/bridge/netfilter/ebt_802_3.c73
-rw-r--r--net/bridge/netfilter/ebt_among.c228
-rw-r--r--net/bridge/netfilter/ebt_arp.c140
-rw-r--r--net/bridge/netfilter/ebt_arpreply.c97
-rw-r--r--net/bridge/netfilter/ebt_dnat.c76
-rw-r--r--net/bridge/netfilter/ebt_ip.c122
-rw-r--r--net/bridge/netfilter/ebt_limit.c113
-rw-r--r--net/bridge/netfilter/ebt_log.c171
-rw-r--r--net/bridge/netfilter/ebt_mark.c68
-rw-r--r--net/bridge/netfilter/ebt_mark_m.c62
-rw-r--r--net/bridge/netfilter/ebt_pkttype.c59
-rw-r--r--net/bridge/netfilter/ebt_redirect.c81
-rw-r--r--net/bridge/netfilter/ebt_snat.c76
-rw-r--r--net/bridge/netfilter/ebt_stp.c194
-rw-r--r--net/bridge/netfilter/ebt_ulog.c295
-rw-r--r--net/bridge/netfilter/ebt_vlan.c195
-rw-r--r--net/bridge/netfilter/ebtable_broute.c86
-rw-r--r--net/bridge/netfilter/ebtable_filter.c123
-rw-r--r--net/bridge/netfilter/ebtable_nat.c130
-rw-r--r--net/bridge/netfilter/ebtables.c1507
22 files changed, 4139 insertions, 0 deletions
diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
new file mode 100644
index 000000000000..68ccef507b49
--- /dev/null
+++ b/net/bridge/netfilter/Kconfig
@@ -0,0 +1,211 @@
+#
+# Bridge netfilter configuration
+#
+
+menu "Bridge: Netfilter Configuration"
+ depends on BRIDGE && NETFILTER
+
+config BRIDGE_NF_EBTABLES
+ tristate "Ethernet Bridge tables (ebtables) support"
+ help
+ ebtables is a general, extensible frame/packet identification
+ framework. Say 'Y' or 'M' here if you want to do Ethernet
+ filtering/NAT/brouting on the Ethernet bridge.
+#
+# tables
+#
+config BRIDGE_EBT_BROUTE
+ tristate "ebt: broute table support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_T_FILTER
+ tristate "ebt: filter table support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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).
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_T_NAT
+ tristate "ebt: nat table support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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).
+
+ To compile it as a module, choose M here. If unsure, say N.
+#
+# matches
+#
+config BRIDGE_EBT_802_3
+ tristate "ebt: 802.3 filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds matching support for 802.3 Ethernet frames.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_AMONG
+ tristate "ebt: among filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the among match, which allows matching the MAC source
+ and/or destination address on a list of addresses. Optionally,
+ MAC/IP address pairs can be matched, f.e. for anti-spoofing rules.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_ARP
+ tristate "ebt: ARP filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the ARP match, which allows ARP and RARP header field
+ filtering.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_IP
+ tristate "ebt: IP filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the IP match, which allows basic IP header field
+ filtering.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_LIMIT
+ tristate "ebt: limit match support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the limit match, which allows you to control
+ the rate at which a rule can be matched. This match is the
+ equivalent of the iptables limit match.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+
+config BRIDGE_EBT_MARK
+ tristate "ebt: mark filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_PKTTYPE
+ tristate "ebt: packet type filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the packet type match, which allows matching on the
+ type of packet based on its Ethernet "class" (as determined by
+ the generic networking code): broadcast, multicast,
+ for this host alone or for another host.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_STP
+ tristate "ebt: STP filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the Spanning Tree Protocol match, which
+ allows STP header field filtering.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_VLAN
+ tristate "ebt: 802.1Q VLAN filter support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the 802.1Q vlan match, which allows the filtering of
+ 802.1Q vlan fields.
+
+ To compile it as a module, choose M here. If unsure, say N.
+#
+# targets
+#
+config BRIDGE_EBT_ARPREPLY
+ tristate "ebt: arp reply target support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the arp reply target, which allows
+ automatically sending arp replies to arp requests.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_DNAT
+ tristate "ebt: dnat target support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the MAC DNAT target, which allows altering the MAC
+ destination address of frames.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_MARK_T
+ tristate "ebt: mark target support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_REDIRECT
+ tristate "ebt: redirect target support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ 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.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_SNAT
+ tristate "ebt: snat target support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the MAC SNAT target, which allows altering the MAC
+ source address of frames.
+
+ To compile it as a module, choose M here. If unsure, say N.
+#
+# watchers
+#
+config BRIDGE_EBT_LOG
+ tristate "ebt: log support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the log watcher, that you can use in any rule
+ in any ebtables table. It records info about the frame header
+ to the syslog.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+config BRIDGE_EBT_ULOG
+ tristate "ebt: ulog support"
+ depends on BRIDGE_NF_EBTABLES
+ help
+ This option adds the ulog watcher, that you can use in any rule
+ in any ebtables table. The packet is passed to a userspace
+ logging daemon using netlink multicast sockets. This differs
+ from the log watcher in the sense that the complete packet is
+ sent to userspace instead of a descriptive text and that
+ netlink multicast sockets are used instead of the syslog.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
+endmenu
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
new file mode 100644
index 000000000000..8bf6d9f6e9d3
--- /dev/null
+++ b/net/bridge/netfilter/Makefile
@@ -0,0 +1,32 @@
+#
+# Makefile for the netfilter modules for Link Layer filtering on a bridge.
+#
+
+obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
+
+# tables
+obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o
+obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
+obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
+
+#matches
+obj-$(CONFIG_BRIDGE_EBT_802_3) += ebt_802_3.o
+obj-$(CONFIG_BRIDGE_EBT_AMONG) += ebt_among.o
+obj-$(CONFIG_BRIDGE_EBT_ARP) += ebt_arp.o
+obj-$(CONFIG_BRIDGE_EBT_IP) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_LIMIT) += ebt_limit.o
+obj-$(CONFIG_BRIDGE_EBT_MARK) += ebt_mark_m.o
+obj-$(CONFIG_BRIDGE_EBT_PKTTYPE) += ebt_pkttype.o
+obj-$(CONFIG_BRIDGE_EBT_STP) += ebt_stp.o
+obj-$(CONFIG_BRIDGE_EBT_VLAN) += ebt_vlan.o
+
+# targets
+obj-$(CONFIG_BRIDGE_EBT_ARPREPLY) += ebt_arpreply.o
+obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
+obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
+obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
+obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
+
+# watchers
+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_ulog.o
diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
new file mode 100644
index 000000000000..468ebdf4bc1c
--- /dev/null
+++ b/net/bridge/netfilter/ebt_802_3.c
@@ -0,0 +1,73 @@
+/*
+ * 802_3
+ *
+ * Author:
+ * Chris Vitale csv@bluetail.com
+ *
+ * May 2003
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_802_3.h>
+#include <linux/module.h>
+
+static int ebt_filter_802_3(const struct sk_buff *skb, const struct net_device *in,
+ const struct net_device *out, const void *data, unsigned int datalen)
+{
+ struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
+ struct ebt_802_3_hdr *hdr = ebt_802_3_hdr(skb);
+ uint16_t type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
+
+ if (info->bitmask & EBT_802_3_SAP) {
+ if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP))
+ return EBT_NOMATCH;
+ if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP))
+ return EBT_NOMATCH;
+ }
+
+ if (info->bitmask & EBT_802_3_TYPE) {
+ if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
+ return EBT_NOMATCH;
+ if (FWINV(info->type != type, EBT_802_3_TYPE))
+ return EBT_NOMATCH;
+ }
+
+ return EBT_MATCH;
+}
+
+static struct ebt_match filter_802_3;
+static int ebt_802_3_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+ struct ebt_802_3_info *info = (struct ebt_802_3_info *)data;
+
+ if (datalen < sizeof(struct ebt_802_3_info))
+ return -EINVAL;
+ if (info->bitmask & ~EBT_802_3_MASK || info->invflags & ~EBT_802_3_MASK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct ebt_match filter_802_3 =
+{
+ .name = EBT_802_3_MATCH,
+ .match = ebt_filter_802_3,
+ .check = ebt_802_3_check,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return ebt_register_match(&filter_802_3);
+}
+
+static void __exit fini(void)
+{
+ ebt_unregister_match(&filter_802_3);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
new file mode 100644
index 000000000000..5a1f5e3bff15
--- /dev/null
+++ b/net/bridge/netfilter/ebt_among.c
@@ -0,0 +1,228 @@
+/*
+ * ebt_among
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ *
+ * August, 2003
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_among.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+
+static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
+ const char *mac, uint32_t ip)
+{
+ /* You may be puzzled as to how this code works.
+ * Some tricks were used, refer to
+ * include/linux/netfilter_bridge/ebt_among.h
+ * as there you can find a solution of this mystery.
+ */
+ const struct ebt_mac_wormhash_tuple *p;
+ int start, limit, i;
+ uint32_t cmp[2] = { 0, 0 };
+ int key = (const unsigned char) mac[5];
+
+ memcpy(((char *) cmp) + 2, mac, 6);
+ start = wh->table[key];
+ limit = wh->table[key + 1];
+ if (ip) {
+ for (i = start; i < limit; i++) {
+ p = &wh->pool[i];
+ if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
+ if (p->ip == 0 || p->ip == ip) {
+ return 1;
+ }
+ }
+ }
+ } else {
+ for (i = start; i < limit; i++) {
+ p = &wh->pool[i];
+ if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
+ if (p->ip == 0) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
+ *wh)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (wh->table[i] > wh->table[i + 1])
+ return -0x100 - i;
+ if (wh->table[i] < 0)
+ return -0x200 - i;
+ if (wh->table[i] > wh->poolsize)
+ return -0x300 - i;
+ }
+ if (wh->table[256] > wh->poolsize)
+ return -0xc00;
+ return 0;
+}
+
+static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
+{
+ if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+ struct iphdr _iph, *ih;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL)
+ return -1;
+ *addr = ih->daddr;
+ } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+ struct arphdr _arph, *ah;
+ uint32_t buf, *bp;
+
+ ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ if (ah == NULL ||
+ ah->ar_pln != sizeof(uint32_t) ||
+ ah->ar_hln != ETH_ALEN)
+ return -1;
+ bp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ 2 * ETH_ALEN + sizeof(uint32_t),
+ sizeof(uint32_t), &buf);
+ if (bp == NULL)
+ return -1;
+ *addr = *bp;
+ }
+ return 0;
+}
+
+static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
+{
+ if (eth_hdr(skb)->h_proto == htons(ETH_P_IP)) {
+ struct iphdr _iph, *ih;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL)
+ return -1;
+ *addr = ih->saddr;
+ } else if (eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
+ struct arphdr _arph, *ah;
+ uint32_t buf, *bp;
+
+ ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ if (ah == NULL ||
+ ah->ar_pln != sizeof(uint32_t) ||
+ ah->ar_hln != ETH_ALEN)
+ return -1;
+ bp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ ETH_ALEN, sizeof(uint32_t), &buf);
+ if (bp == NULL)
+ return -1;
+ *addr = *bp;
+ }
+ return 0;
+}
+
+static int ebt_filter_among(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out, const void *data,
+ unsigned int datalen)
+{
+ struct ebt_among_info *info = (struct ebt_among_info *) data;
+ const char *dmac, *smac;
+ const struct ebt_mac_wormhash *wh_dst, *wh_src;
+ uint32_t dip = 0, sip = 0;
+
+ wh_dst = ebt_among_wh_dst(info);
+ wh_src = ebt_among_wh_src(info);
+
+ if (wh_src) {
+ smac = eth_hdr(skb)->h_source;
+ if (get_ip_src(skb, &sip))
+ return EBT_NOMATCH;
+ if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
+ /* we match only if it contains */
+ if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
+ return EBT_NOMATCH;
+ } else {
+ /* we match only if it DOES NOT contain */
+ if (ebt_mac_wormhash_contains(wh_src, smac, sip))
+ return EBT_NOMATCH;
+ }
+ }
+
+ if (wh_dst) {
+ dmac = eth_hdr(skb)->h_dest;
+ if (get_ip_dst(skb, &dip))
+ return EBT_NOMATCH;
+ if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
+ /* we match only if it contains */
+ if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
+ return EBT_NOMATCH;
+ } else {
+ /* we match only if it DOES NOT contain */
+ if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
+ return EBT_NOMATCH;
+ }
+ }
+
+ return EBT_MATCH;
+}
+
+static int ebt_among_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data,
+ unsigned int datalen)
+{
+ struct ebt_among_info *info = (struct ebt_among_info *) data;
+ int expected_length = sizeof(struct ebt_among_info);
+ const struct ebt_mac_wormhash *wh_dst, *wh_src;
+ int err;
+
+ wh_dst = ebt_among_wh_dst(info);
+ wh_src = ebt_among_wh_src(info);
+ expected_length += ebt_mac_wormhash_size(wh_dst);
+ expected_length += ebt_mac_wormhash_size(wh_src);
+
+ if (datalen != EBT_ALIGN(expected_length)) {
+ printk(KERN_WARNING
+ "ebtables: among: wrong size: %d"
+ "against expected %d, rounded to %Zd\n",
+ datalen, expected_length,
+ EBT_ALIGN(expected_length));
+ return -EINVAL;
+ }
+ if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
+ printk(KERN_WARNING
+ "ebtables: among: dst integrity fail: %x\n", -err);
+ return -EINVAL;
+ }
+ if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
+ printk(KERN_WARNING
+ "ebtables: among: src integrity fail: %x\n", -err);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct ebt_match filter_among = {
+ .name = EBT_AMONG_MATCH,
+ .match = ebt_filter_among,
+ .check = ebt_among_check,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return ebt_register_match(&filter_among);
+}
+
+static void __exit fini(void)
+{
+ ebt_unregister_match(&filter_among);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
new file mode 100644
index 000000000000..b94c48cb6e4b
--- /dev/null
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -0,0 +1,140 @@
+/*
+ * ebt_arp
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@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/if_ether.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;
+ struct arphdr _arph, *ah;
+
+ ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ if (ah == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
+ ah->ar_op, EBT_ARP_OPCODE))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
+ ah->ar_hrd, EBT_ARP_HTYPE))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
+ ah->ar_pro, EBT_ARP_PTYPE))
+ return EBT_NOMATCH;
+
+ if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
+ uint32_t _addr, *ap;
+
+ /* IPv4 addresses are always 4 bytes */
+ if (ah->ar_pln != sizeof(uint32_t))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_SRC_IP) {
+ ap = skb_header_pointer(skb, sizeof(struct arphdr) +
+ ah->ar_hln, sizeof(_addr),
+ &_addr);
+ if (ap == NULL)
+ return EBT_NOMATCH;
+ if (FWINV(info->saddr != (*ap & info->smsk),
+ EBT_ARP_SRC_IP))
+ return EBT_NOMATCH;
+ }
+
+ if (info->bitmask & EBT_ARP_DST_IP) {
+ ap = skb_header_pointer(skb, sizeof(struct arphdr) +
+ 2*ah->ar_hln+sizeof(uint32_t),
+ sizeof(_addr), &_addr);
+ if (ap == NULL)
+ return EBT_NOMATCH;
+ if (FWINV(info->daddr != (*ap & info->dmsk),
+ EBT_ARP_DST_IP))
+ return EBT_NOMATCH;
+ }
+ }
+
+ if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
+ unsigned char _mac[ETH_ALEN], *mp;
+ uint8_t verdict, i;
+
+ /* MAC addresses are 6 bytes */
+ if (ah->ar_hln != ETH_ALEN)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_SRC_MAC) {
+ mp = skb_header_pointer(skb, sizeof(struct arphdr),
+ sizeof(_mac), &_mac);
+ if (mp == NULL)
+ return EBT_NOMATCH;
+ verdict = 0;
+ for (i = 0; i < 6; i++)
+ verdict |= (mp[i] ^ info->smaddr[i]) &
+ info->smmsk[i];
+ if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
+ return EBT_NOMATCH;
+ }
+
+ if (info->bitmask & EBT_ARP_DST_MAC) {
+ mp = skb_header_pointer(skb, sizeof(struct arphdr) +
+ ah->ar_hln + ah->ar_pln,
+ sizeof(_mac), &_mac);
+ if (mp == NULL)
+ return EBT_NOMATCH;
+ verdict = 0;
+ for (i = 0; i < 6; i++)
+ verdict |= (mp[i] ^ info->dmaddr[i]) &
+ info->dmmsk[i];
+ if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
+ 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 != EBT_ALIGN(sizeof(struct ebt_arp_info)))
+ return -EINVAL;
+ if ((e->ethproto != htons(ETH_P_ARP) &&
+ e->ethproto != 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 =
+{
+ .name = EBT_ARP_MATCH,
+ .match = ebt_filter_arp,
+ .check = ebt_arp_check,
+ .me = 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/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
new file mode 100644
index 000000000000..b934de90f7c5
--- /dev/null
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -0,0 +1,97 @@
+/*
+ * ebt_arpreply
+ *
+ * Authors:
+ * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * August, 2003
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_arpreply.h>
+#include <linux/if_arp.h>
+#include <net/arp.h>
+#include <linux/module.h>
+
+static int ebt_target_reply(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_arpreply_info *info = (struct ebt_arpreply_info *)data;
+ u32 _sip, *siptr, _dip, *diptr;
+ struct arphdr _ah, *ap;
+ unsigned char _sha[ETH_ALEN], *shp;
+ struct sk_buff *skb = *pskb;
+
+ ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
+ if (ap == NULL)
+ return EBT_DROP;
+
+ if (ap->ar_op != htons(ARPOP_REQUEST) ||
+ ap->ar_hln != ETH_ALEN ||
+ ap->ar_pro != htons(ETH_P_IP) ||
+ ap->ar_pln != 4)
+ return EBT_CONTINUE;
+
+ shp = skb_header_pointer(skb, sizeof(_ah), ETH_ALEN, &_sha);
+ if (shp == NULL)
+ return EBT_DROP;
+
+ siptr = skb_header_pointer(skb, sizeof(_ah) + ETH_ALEN,
+ sizeof(_sip), &_sip);
+ if (siptr == NULL)
+ return EBT_DROP;
+
+ diptr = skb_header_pointer(skb,
+ sizeof(_ah) + 2 * ETH_ALEN + sizeof(_sip),
+ sizeof(_dip), &_dip);
+ if (diptr == NULL)
+ return EBT_DROP;
+
+ arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in,
+ *diptr, shp, info->mac, shp);
+
+ return info->target;
+}
+
+static int ebt_target_reply_check(const char *tablename, unsigned int hookmask,
+ const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+ struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
+
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info)))
+ return -EINVAL;
+ if (BASE_CHAIN && info->target == EBT_RETURN)
+ return -EINVAL;
+ if (e->ethproto != htons(ETH_P_ARP) ||
+ e->invflags & EBT_IPROTO)
+ return -EINVAL;
+ CLEAR_BASE_CHAIN_BIT;
+ if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING))
+ return -EINVAL;
+ return 0;
+}
+
+static struct ebt_target reply_target =
+{
+ .name = EBT_ARPREPLY_TARGET,
+ .target = ebt_target_reply,
+ .check = ebt_target_reply_check,
+ .me = THIS_MODULE,
+};
+
+static int __init init(void)
+{
+ return ebt_register_target(&reply_target);
+}
+
+static void __exit fini(void)
+{
+ ebt_unregister_target(&reply_target);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
new file mode 100644
index 000000000000..f5463086c7bd
--- /dev/null
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -0,0 +1,76 @@
+/*
+ * ebt_dnat
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@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;
+
+ if (skb_shared(*pskb) || skb_cloned(*pskb)) {
+ struct sk_buff *nskb;
+
+ nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb)
+ return NF_DROP;
+ if ((*pskb)->sk)
+ skb_set_owner_w(nskb, (*pskb)->sk);
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ }
+ memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN);
+ 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 != EBT_ALIGN(sizeof(struct ebt_nat_info)))
+ return -EINVAL;
+ if (INVALID_TARGET)
+ return -EINVAL;
+ return 0;
+}
+
+static struct ebt_target dnat =
+{
+ .name = EBT_DNAT_TARGET,
+ .target = ebt_target_dnat,
+ .check = ebt_target_dnat_check,
+ .me = 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/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
new file mode 100644
index 000000000000..7323805b9726
--- /dev/null
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -0,0 +1,122 @@
+/*
+ * ebt_ip
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * April, 2002
+ *
+ * Changes:
+ * added ip-sport and ip-dport
+ * Innominate Security Technologies AG <mhopf@innominate.com>
+ * September, 2002
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/module.h>
+
+struct tcpudphdr {
+ uint16_t src;
+ uint16_t dst;
+};
+
+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;
+ struct iphdr _iph, *ih;
+ struct tcpudphdr _ports, *pptr;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP_TOS &&
+ FWINV(info->tos != ih->tos, EBT_IP_TOS))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP_SOURCE &&
+ FWINV((ih->saddr & info->smsk) !=
+ info->saddr, EBT_IP_SOURCE))
+ return EBT_NOMATCH;
+ if ((info->bitmask & EBT_IP_DEST) &&
+ FWINV((ih->daddr & info->dmsk) !=
+ info->daddr, EBT_IP_DEST))
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP_PROTO) {
+ if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
+ return EBT_NOMATCH;
+ if (!(info->bitmask & EBT_IP_DPORT) &&
+ !(info->bitmask & EBT_IP_SPORT))
+ return EBT_MATCH;
+ pptr = skb_header_pointer(skb, ih->ihl*4,
+ sizeof(_ports), &_ports);
+ if (pptr == NULL)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_IP_DPORT) {
+ u32 dst = ntohs(pptr->dst);
+ if (FWINV(dst < info->dport[0] ||
+ dst > info->dport[1],
+ EBT_IP_DPORT))
+ return EBT_NOMATCH;
+ }
+ if (info->bitmask & EBT_IP_SPORT) {
+ u32 src = ntohs(pptr->src);
+ if (FWINV(src < info->sport[0] ||
+ src > info->sport[1],
+ EBT_IP_SPORT))
+ 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 *)dat