blob: a073dffe7a11e1993eeade9d6f65acc87e3960f2 [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 Engelhardt2d06d4a2008-10-08 11:35:15 +020018static bool
19ebt_arp_mt(const struct sk_buff *skb, const struct net_device *in,
20 const struct net_device *out, const struct xt_match *match,
21 const void *data, int offset, unsigned int protoff, bool *hotdrop)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022{
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080023 const struct ebt_arp_info *info = data;
24 const struct arphdr *ah;
25 struct arphdr _arph;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27 ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
28 if (ah == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020029 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
31 ah->ar_op, EBT_ARP_OPCODE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020032 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
34 ah->ar_hrd, EBT_ARP_HTYPE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020035 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
37 ah->ar_pro, EBT_ARP_PTYPE))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020038 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Bart De Schuymere011ff42007-11-05 20:59:47 -080040 if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080041 const __be32 *sap, *dap;
42 __be32 saddr, daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070044 if (ah->ar_pln != sizeof(__be32) || ah->ar_pro != htons(ETH_P_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020045 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070046 sap = skb_header_pointer(skb, sizeof(struct arphdr) +
47 ah->ar_hln, sizeof(saddr),
48 &saddr);
49 if (sap == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020050 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070051 dap = skb_header_pointer(skb, sizeof(struct arphdr) +
52 2*ah->ar_hln+sizeof(saddr),
53 sizeof(daddr), &daddr);
54 if (dap == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020055 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070056 if (info->bitmask & EBT_ARP_SRC_IP &&
57 FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020058 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070059 if (info->bitmask & EBT_ARP_DST_IP &&
60 FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020061 return false;
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070062 if (info->bitmask & EBT_ARP_GRAT &&
63 FWINV(*dap != *sap, EBT_ARP_GRAT))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020064 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 }
66
67 if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -080068 const unsigned char *mp;
69 unsigned char _mac[ETH_ALEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 uint8_t verdict, i;
71
Bart De Schuymerc15bf6e2007-04-12 22:15:06 -070072 if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020073 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 if (info->bitmask & EBT_ARP_SRC_MAC) {
75 mp = skb_header_pointer(skb, sizeof(struct arphdr),
76 sizeof(_mac), &_mac);
77 if (mp == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020078 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 verdict = 0;
80 for (i = 0; i < 6; i++)
81 verdict |= (mp[i] ^ info->smaddr[i]) &
82 info->smmsk[i];
83 if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020084 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 }
86
87 if (info->bitmask & EBT_ARP_DST_MAC) {
88 mp = skb_header_pointer(skb, sizeof(struct arphdr) +
89 ah->ar_hln + ah->ar_pln,
90 sizeof(_mac), &_mac);
91 if (mp == NULL)
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020092 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 verdict = 0;
94 for (i = 0; i < 6; i++)
95 verdict |= (mp[i] ^ info->dmaddr[i]) &
96 info->dmmsk[i];
97 if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
Jan Engelhardt8cc784e2008-10-08 11:35:13 +020098 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 }
101
Jan Engelhardt8cc784e2008-10-08 11:35:13 +0200102 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200105static bool
106ebt_arp_mt_check(const char *table, const void *entry,
107 const struct xt_match *match, void *data,
108 unsigned int hook_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
Jan Engelhardtabfdf1c2008-01-31 03:59:24 -0800110 const struct ebt_arp_info *info = data;
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200111 const struct ebt_entry *e = entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 if ((e->ethproto != htons(ETH_P_ARP) &&
114 e->ethproto != htons(ETH_P_RARP)) ||
115 e->invflags & EBT_IPROTO)
Jan Engelhardt19eda872008-10-08 11:35:13 +0200116 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
Jan Engelhardt19eda872008-10-08 11:35:13 +0200118 return false;
119 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120}
121
Jan Engelhardt043ef462008-10-08 11:35:15 +0200122static struct xt_match ebt_arp_mt_reg __read_mostly = {
123 .name = "arp",
Jan Engelhardt001a18d2008-10-08 11:35:14 +0200124 .revision = 0,
125 .family = NFPROTO_BRIDGE,
Jan Engelhardt2d06d4a2008-10-08 11:35:15 +0200126 .match = ebt_arp_mt,
127 .checkentry = ebt_arp_mt_check,
Jan Engelhardt18219d32008-10-08 11:35:13 +0200128 .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 .me = THIS_MODULE,
130};
131
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800132static int __init ebt_arp_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200134 return xt_register_match(&ebt_arp_mt_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135}
136
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800137static void __exit ebt_arp_fini(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
Jan Engelhardt043ef462008-10-08 11:35:15 +0200139 xt_unregister_match(&ebt_arp_mt_reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140}
141
Andrew Morton65b4b4e2006-03-28 16:37:06 -0800142module_init(ebt_arp_init);
143module_exit(ebt_arp_fini);
Jan Engelhardtf776c4c2008-01-31 04:00:30 -0800144MODULE_DESCRIPTION("Ebtables: ARP protocol packet match");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145MODULE_LICENSE("GPL");