diff options
author | Bart De Schuymer <bdschuym@pandora.be> | 2007-04-13 01:15:06 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-26 01:28:58 -0400 |
commit | c15bf6e699f4c366f2d1e19ac5d7add21c6b5a19 (patch) | |
tree | 2bcd680115a8b07cd6d7493b134ae2d36fe637be | |
parent | 516299d2f5b6f9703b9b388faf91898dc636a678 (diff) |
[NETFILTER]: ebt_arp: add gratuitous arp filtering
The attached patch adds gratuitous arp filtering, more precisely: it
allows checking that the IPv4 source address matches the IPv4
destination address inside the ARP header. It also adds a check for the
hardware address type when matching MAC addresses (nothing critical,
just for better consistency).
Signed-off-by: Bart De Schuymer <bdschuym@pandora.be>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter_bridge/ebt_arp.h | 4 | ||||
-rw-r--r-- | net/bridge/netfilter/ebt_arp.c | 48 |
2 files changed, 25 insertions, 27 deletions
diff --git a/include/linux/netfilter_bridge/ebt_arp.h b/include/linux/netfilter_bridge/ebt_arp.h index 97e4dbde1f89..cbf4843b6b0f 100644 --- a/include/linux/netfilter_bridge/ebt_arp.h +++ b/include/linux/netfilter_bridge/ebt_arp.h | |||
@@ -8,8 +8,10 @@ | |||
8 | #define EBT_ARP_DST_IP 0x10 | 8 | #define EBT_ARP_DST_IP 0x10 |
9 | #define EBT_ARP_SRC_MAC 0x20 | 9 | #define EBT_ARP_SRC_MAC 0x20 |
10 | #define EBT_ARP_DST_MAC 0x40 | 10 | #define EBT_ARP_DST_MAC 0x40 |
11 | #define EBT_ARP_GRAT 0x80 | ||
11 | #define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \ | 12 | #define EBT_ARP_MASK (EBT_ARP_OPCODE | EBT_ARP_HTYPE | EBT_ARP_PTYPE | \ |
12 | EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC) | 13 | EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC | \ |
14 | EBT_ARP_GRAT) | ||
13 | #define EBT_ARP_MATCH "arp" | 15 | #define EBT_ARP_MATCH "arp" |
14 | 16 | ||
15 | struct ebt_arp_info | 17 | struct ebt_arp_info |
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index 9c599800a900..1a46952a56d9 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c | |||
@@ -35,40 +35,36 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in | |||
35 | return EBT_NOMATCH; | 35 | return EBT_NOMATCH; |
36 | 36 | ||
37 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { | 37 | if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) { |
38 | __be32 _addr, *ap; | 38 | __be32 saddr, daddr, *sap, *dap; |
39 | 39 | ||
40 | /* IPv4 addresses are always 4 bytes */ | 40 | if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP)) |
41 | if (ah->ar_pln != sizeof(__be32)) | 41 | return EBT_NOMATCH; |
42 | sap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
43 | ah->ar_hln, sizeof(saddr), | ||
44 | &saddr); | ||
45 | if (sap == NULL) | ||
46 | return EBT_NOMATCH; | ||
47 | dap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
48 | 2*ah->ar_hln+sizeof(saddr), | ||
49 | sizeof(daddr), &daddr); | ||
50 | if (dap == NULL) | ||
51 | return EBT_NOMATCH; | ||
52 | if (info->bitmask & EBT_ARP_SRC_IP && | ||
53 | FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) | ||
54 | return EBT_NOMATCH; | ||
55 | if (info->bitmask & EBT_ARP_DST_IP && | ||
56 | FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) | ||
57 | return EBT_NOMATCH; | ||
58 | if (info->bitmask & EBT_ARP_GRAT && | ||
59 | FWINV(*dap != *sap, EBT_ARP_GRAT)) | ||
42 | return EBT_NOMATCH; | 60 | return EBT_NOMATCH; |
43 | if (info->bitmask & EBT_ARP_SRC_IP) { | ||
44 | ap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
45 | ah->ar_hln, sizeof(_addr), | ||
46 | &_addr); | ||
47 | if (ap == NULL) | ||
48 | return EBT_NOMATCH; | ||
49 | if (FWINV(info->saddr != (*ap & info->smsk), | ||
50 | EBT_ARP_SRC_IP)) | ||
51 | return EBT_NOMATCH; | ||
52 | } | ||
53 | |||
54 | if (info->bitmask & EBT_ARP_DST_IP) { | ||
55 | ap = skb_header_pointer(skb, sizeof(struct arphdr) + | ||
56 | 2*ah->ar_hln+sizeof(__be32), | ||
57 | sizeof(_addr), &_addr); | ||
58 | if (ap == NULL) | ||
59 | return EBT_NOMATCH; | ||
60 | if (FWINV(info->daddr != (*ap & info->dmsk), | ||
61 | EBT_ARP_DST_IP)) | ||
62 | return EBT_NOMATCH; | ||
63 | } | ||
64 | } | 61 | } |
65 | 62 | ||
66 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { | 63 | if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { |
67 | unsigned char _mac[ETH_ALEN], *mp; | 64 | unsigned char _mac[ETH_ALEN], *mp; |
68 | uint8_t verdict, i; | 65 | uint8_t verdict, i; |
69 | 66 | ||
70 | /* MAC addresses are 6 bytes */ | 67 | if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) |
71 | if (ah->ar_hln != ETH_ALEN) | ||
72 | return EBT_NOMATCH; | 68 | return EBT_NOMATCH; |
73 | if (info->bitmask & EBT_ARP_SRC_MAC) { | 69 | if (info->bitmask & EBT_ARP_SRC_MAC) { |
74 | mp = skb_header_pointer(skb, sizeof(struct arphdr), | 70 | mp = skb_header_pointer(skb, sizeof(struct arphdr), |