blob: 4a5226cbab89107bd66c6785c3a6fb16a9795ec9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ebt_arp
3 *
4 * Authors:
5 * Bart De Schuymer <bdschuym@pandora.be>
6 * Tim Gardner <timg@tpi.com>
7 *
8 * April, 2002
9 *
10 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/if_arp.h>
12#include <linux/if_ether.h>
13#include <linux/module.h>
Jan Engelhardt18219d32008-10-08 11:35:13 +020014#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter_bridge/ebtables.h>
16#include <linux/netfilter_bridge/ebt_arp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020018static bool ebt_filter_arp(const struct sk_buff *skb,
19 const struct net_device *in,
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 const struct net_device *out, const void *data, unsigned int datalen)
21{
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080022 const struct ebt_arp_info *info = data;
23 const struct arphdr *ah;
24 struct arphdr _arph;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26 ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
27 if (ah == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020028 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
30 ah->ar_op, EBT_ARP_OPCODE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020031 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070032 if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
33 ah->ar_hrd, EBT_ARP_HTYPE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020034 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
36 ah->ar_pro, EBT_ARP_PTYPE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020037 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Bart De Schuymere011ff42007-11-05 20:59:47 -080039 if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080040 const __be32 *sap, *dap;
41 __be32 saddr, daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070043 if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020044 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070045 sap = skb_header_pointer(skb, sizeof(struct arphdr) +
46 ah->ar_hln, sizeof(saddr),
47 &saddr);
48 if (sap == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020049 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070050 dap = skb_header_pointer(skb, sizeof(struct arphdr) +
51 2*ah->ar_hln+sizeof(saddr),
52 sizeof(daddr), &daddr);
53 if (dap == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020054 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070055 if (info->bitmask & EBT_ARP_SRC_IP &&
56 FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020057 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070058 if (info->bitmask & EBT_ARP_DST_IP &&
59 FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020060 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070061 if (info->bitmask & EBT_ARP_GRAT &&
62 FWINV(*dap != *sap, EBT_ARP_GRAT))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020063 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 }
65
66 if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080067 const unsigned char *mp;
68 unsigned char _mac[ETH_ALEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 uint8_t verdict, i;
70
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070071 if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020072 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 if (info->bitmask & EBT_ARP_SRC_MAC) {
74 mp = skb_header_pointer(skb, sizeof(struct arphdr),
75 sizeof(_mac), &_mac);
76 if (mp == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020077 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 verdict = 0;
79 for (i = 0; i < 6; i++)
80 verdict |= (mp[i] ^ info->smaddr[i]) &
81 info->smmsk[i];
82 if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020083 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
85
86 if (info->bitmask & EBT_ARP_DST_MAC) {
87 mp = skb_header_pointer(skb, sizeof(struct arphdr) +
88 ah->ar_hln + ah->ar_pln,
89 sizeof(_mac), &_mac);
90 if (mp == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020091 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 verdict = 0;
93 for (i = 0; i < 6; i++)
94 verdict |= (mp[i] ^ info->dmaddr[i]) &
95 info->dmmsk[i];
96 if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020097 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 }
99 }
100
Jan Engelhardt8cc784e2008-10-08 11:35:13 +0200101 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
Jan Engelhardt19eda872008-10-08 11:35:13 +0200104static bool ebt_arp_check(const char *tablename, unsigned int hookmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 const struct ebt_entry *e, void *data, unsigned int datalen)
106{
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -0800107 const struct ebt_arp_info *info = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if ((e->ethproto != htons(ETH_P_ARP) &&
110 e->ethproto != htons(ETH_P_RARP)) ||
111 e->invflags & EBT_IPROTO)
Jan Engelhardt19eda872008-10-08 11:35:13 +0200112 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
Jan Engelhardt19eda872008-10-08 11:35:13 +0200114 return false;
115 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116}
117
Jan Engelhardt30083c92008-01-31 04:00:59 -0800118static struct ebt_match filter_arp __read_mostly = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 .name = EBT_ARP_MATCH,
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200120 .revision = 0,
121 .family = NFPROTO_BRIDGE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 .match = ebt_filter_arp,
123 .check = ebt_arp_check,
Jan Engelhardt18219d32008-10-08 11:35:13 +0200124 .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 .me = THIS_MODULE,
126};
127
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800128static int __init ebt_arp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
130 return ebt_register_match(&filter_arp);
131}
132
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800133static void __exit ebt_arp_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 ebt_unregister_match(&filter_arp);
136}
137
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800138module_init(ebt_arp_init);
139module_exit(ebt_arp_fini);
Jan Engelhardtf776c4c2008-01-31 04:00:30 -0800140MODULE_DESCRIPTION("Ebtables: ARP protocol packet match");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141MODULE_LICENSE("GPL");