]> git.neil.brown.name Git - history.git/commitdiff
[EBTABLES]: Add ARP MAC address filtering.
authorBart De Schuymer <bdschuym@pandora.be>
Sat, 3 May 2003 23:22:27 +0000 (16:22 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Sat, 3 May 2003 23:22:27 +0000 (16:22 -0700)
include/linux/netfilter_bridge/ebt_arp.h
net/bridge/netfilter/ebt_arp.c

index 8967ddae114d48cfd24896d069ef81b34e8858b3..537ec6b487a2ce1f39cdbb8fc9ce9b089309d6d2 100644 (file)
@@ -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;
 };
index 35d2608693679cb296d5f5271e61a8ce236b64f1..106d13d3ded834bd5a424fc2778b5aa3fe3592b6 100644 (file)
@@ -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;
 }