summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBart De Schuymer <bdschuym@pandora.be>2003-05-03 16:22:27 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2003-05-03 16:22:27 -0700
commitfbbcf1fed6fc0097eb24a20e35bbc4659c9aa3f0 (patch)
treeab31e65734c18edbde9f9b73f19f908f3cbd4d9f
parentc6a8dbb549f2caceedb6781203f69f60102b2759 (diff)
[EBTABLES]: Add ARP MAC address filtering.
-rw-r--r--include/linux/netfilter_bridge/ebt_arp.h8
-rw-r--r--net/bridge/netfilter/ebt_arp.c47
2 files changed, 54 insertions, 1 deletions
diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/linux/netfilter_bridge/ebt_arp.h
index 8967ddae114d..537ec6b487a2 100644
--- a/include/linux/netfilter_bridge/ebt_arp.h
+++ b/include/linux/netfilter_bridge/ebt_arp.h
@@ -6,8 +6,10 @@
#define EBT_ARP_PTYPE 0x04
#define EBT_ARP_SRC_IP 0x08
#define EBT_ARP_DST_IP 0x10
+#define EBT_ARP_SRC_MAC 0x20
+#define EBT_ARP_DST_MAC 0x40
#define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \
- EBT_ARP_SRC_IP | EBT_ARP_DST_IP)
+ EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)
#define EBT_ARP_MATCH "arp"
struct ebt_arp_info
@@ -19,6 +21,10 @@ struct ebt_arp_info
uint32_t smsk;
uint32_t daddr;
uint32_t dmsk;
+ unsigned char smaddr[ETH_ALEN];
+ unsigned char smmsk[ETH_ALEN];
+ unsigned char dmaddr[ETH_ALEN];
+ unsigned char dmmsk[ETH_ALEN];
uint8_t bitmask;
uint8_t invflags;
};
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index 35d260869367..106d13d3ded8 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -12,6 +12,7 @@
#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,
@@ -61,6 +62,52 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
return EBT_NOMATCH;
}
}
+
+ if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC))
+ {
+ uint32_t arp_len = sizeof(struct arphdr) +
+ (2 * (((*skb).nh.arph)->ar_hln)) +
+ (2 * (((*skb).nh.arph)->ar_pln));
+ unsigned char dst[ETH_ALEN];
+ unsigned char src[ETH_ALEN];
+
+ /* Make sure the packet is long enough */
+ if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
+ return EBT_NOMATCH;
+ /* MAC addresses are 6 bytes */
+ if (((*skb).nh.arph)->ar_hln != ETH_ALEN)
+ return EBT_NOMATCH;
+ if (info->bitmask & EBT_ARP_SRC_MAC) {
+ uint8_t verdict, i;
+
+ memcpy(&src, ((*skb).nh.raw) +
+ sizeof(struct arphdr),
+ ETH_ALEN);
+ verdict = 0;
+ for (i = 0; i < 6; i++)
+ verdict |= (src[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) {
+ uint8_t verdict, i;
+
+ memcpy(&dst, ((*skb).nh.raw) +
+ sizeof(struct arphdr) +
+ (((*skb).nh.arph)->ar_hln) +
+ (((*skb).nh.arph)->ar_pln),
+ ETH_ALEN);
+ verdict = 0;
+ for (i = 0; i < 6; i++)
+ verdict |= (dst[i] ^ info->dmaddr[i]) &
+ info->dmmsk[i];
+ if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
+ return EBT_NOMATCH;
+ }
+ }
+
return EBT_MATCH;
}