blob: 16cec6d7aa1277123f5d0336bf940fbf6c276302 [file] [log] [blame]
Bart De Schuymere5ed2162002-09-16 20:02:51 +00001/*
2 * ebt_arp
3 *
4 * Authors:
Bart De Schuymer42a25de2003-03-01 12:24:14 +00005 * Bart De Schuymer <bdschuym@pandora.be>
Bart De Schuymere5ed2162002-09-16 20:02:51 +00006 * Tim Gardner <timg@tpi.com>
7 *
8 * April, 2002
9 *
10 */
11
12#include <linux/netfilter_bridge/ebtables.h>
13#include <linux/netfilter_bridge/ebt_arp.h>
14#include <linux/if_arp.h>
Bart De Schuymer8f386472003-05-03 18:13:34 +000015#include <linux/if_ether.h>
Bart De Schuymer5ba73492003-06-01 17:14:02 +000016#include <linux/module.h>
Bart De Schuymere5ed2162002-09-16 20:02:51 +000017
18static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
19 const struct net_device *out, const void *data, unsigned int datalen)
20{
21 struct ebt_arp_info *info = (struct ebt_arp_info *)data;
Bart De Schuymer5ba73492003-06-01 17:14:02 +000022 struct arphdr arph;
Bart De Schuymere5ed2162002-09-16 20:02:51 +000023
Bart De Schuymer5ba73492003-06-01 17:14:02 +000024 if (skb_copy_bits(skb, 0, &arph, sizeof(arph)))
25 return EBT_NOMATCH;
Bart De Schuymere5ed2162002-09-16 20:02:51 +000026 if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
Bart De Schuymer5ba73492003-06-01 17:14:02 +000027 arph.ar_op, EBT_ARP_OPCODE))
Bart De Schuymere5ed2162002-09-16 20:02:51 +000028 return EBT_NOMATCH;
29 if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
Bart De Schuymer5ba73492003-06-01 17:14:02 +000030 arph.ar_hrd, EBT_ARP_HTYPE))
Bart De Schuymere5ed2162002-09-16 20:02:51 +000031 return EBT_NOMATCH;
32 if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
Bart De Schuymer5ba73492003-06-01 17:14:02 +000033 arph.ar_pro, EBT_ARP_PTYPE))
Bart De Schuymere5ed2162002-09-16 20:02:51 +000034 return EBT_NOMATCH;
35
Bart De Schuymer5ba73492003-06-01 17:14:02 +000036 if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
37 uint32_t addr;
Bart De Schuymere5ed2162002-09-16 20:02:51 +000038
Bart De Schuymer8ed17d12003-03-02 15:18:08 +000039 /* IPv4 addresses are always 4 bytes */
Bart De Schuymer5ba73492003-06-01 17:14:02 +000040 if (arph.ar_pln != sizeof(uint32_t))
Bart De Schuymere5ed2162002-09-16 20:02:51 +000041 return EBT_NOMATCH;
Bart De Schuymere5ed2162002-09-16 20:02:51 +000042 if (info->bitmask & EBT_ARP_SRC_IP) {
Bart De Schuymer5ba73492003-06-01 17:14:02 +000043 if (skb_copy_bits(skb, sizeof(struct arphdr) +
44 arph.ar_hln, &addr, sizeof(addr)))
45 return EBT_NOMATCH;
46 if (FWINV(info->saddr != (addr & info->smsk),
Bart De Schuymere5ed2162002-09-16 20:02:51 +000047 EBT_ARP_SRC_IP))
48 return EBT_NOMATCH;
49 }
50
51 if (info->bitmask & EBT_ARP_DST_IP) {
Bart De Schuymer5ba73492003-06-01 17:14:02 +000052 if (skb_copy_bits(skb, sizeof(struct arphdr) +
53 2*arph.ar_hln + sizeof(uint32_t), &addr,
54 sizeof(addr)))
55 return EBT_NOMATCH;
56 if (FWINV(info->daddr != (addr & info->dmsk),
Bart De Schuymere5ed2162002-09-16 20:02:51 +000057 EBT_ARP_DST_IP))
58 return EBT_NOMATCH;
59 }
60 }
Bart De Schuymer8f386472003-05-03 18:13:34 +000061
Bart De Schuymer5ba73492003-06-01 17:14:02 +000062 if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
63 unsigned char mac[ETH_ALEN];
64 uint8_t verdict, i;
Bart De Schuymer8f386472003-05-03 18:13:34 +000065
Bart De Schuymer8f386472003-05-03 18:13:34 +000066 /* MAC addresses are 6 bytes */
Bart De Schuymer5ba73492003-06-01 17:14:02 +000067 if (arph.ar_hln != ETH_ALEN)
Bart De Schuymer8f386472003-05-03 18:13:34 +000068 return EBT_NOMATCH;
69 if (info->bitmask & EBT_ARP_SRC_MAC) {
Bart De Schuymer5ba73492003-06-01 17:14:02 +000070 if (skb_copy_bits(skb, sizeof(struct arphdr), &mac,
71 ETH_ALEN))
72 return EBT_NOMATCH;
Bart De Schuymer8f386472003-05-03 18:13:34 +000073 verdict = 0;
74 for (i = 0; i < 6; i++)
Bart De Schuymer5ba73492003-06-01 17:14:02 +000075 verdict |= (mac[i] ^ info->smaddr[i]) &
Bart De Schuymer8f386472003-05-03 18:13:34 +000076 info->smmsk[i];
77 if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
78 return EBT_NOMATCH;
79 }
80
81 if (info->bitmask & EBT_ARP_DST_MAC) {
Bart De Schuymer5ba73492003-06-01 17:14:02 +000082 if (skb_copy_bits(skb, sizeof(struct arphdr) +
83 arph.ar_hln + arph.ar_pln, &mac, ETH_ALEN))
84 return EBT_NOMATCH;
Bart De Schuymer8f386472003-05-03 18:13:34 +000085 verdict = 0;
86 for (i = 0; i < 6; i++)
Bart De Schuymer5ba73492003-06-01 17:14:02 +000087 verdict |= (mac[i] ^ info->dmaddr[i]) &
Bart De Schuymer8f386472003-05-03 18:13:34 +000088 info->dmmsk[i];
89 if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
90 return EBT_NOMATCH;
91 }
92 }
93
Bart De Schuymere5ed2162002-09-16 20:02:51 +000094 return EBT_MATCH;
95}
96
Bart De Schuymerff871722003-06-03 18:47:33 +000097static struct ebt_match filter_arp;
Bart De Schuymere5ed2162002-09-16 20:02:51 +000098static int ebt_arp_check(const char *tablename, unsigned int hookmask,
Bart De Schuymerff871722003-06-03 18:47:33 +000099 const struct ebt_entry *e, void *data, unsigned int datalen,
100 unsigned int version)
Bart De Schuymere5ed2162002-09-16 20:02:51 +0000101{
102 struct ebt_arp_info *info = (struct ebt_arp_info *)data;
103
104 if (datalen != sizeof(struct ebt_arp_info))
105 return -EINVAL;
Bart De Schuymerff871722003-06-03 18:47:33 +0000106 if (ebt_check_version(version, filter_arp.version, filter_arp.name))
107 return -EINVAL;
Bart De Schuymere5ed2162002-09-16 20:02:51 +0000108 if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
109 e->ethproto != __constant_htons(ETH_P_RARP)) ||
110 e->invflags & EBT_IPROTO)
111 return -EINVAL;
112 if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
113 return -EINVAL;
114 return 0;
115}
116
117static struct ebt_match filter_arp =
118{
Bart De Schuymer8ed17d12003-03-02 15:18:08 +0000119 .name = EBT_ARP_MATCH,
120 .match = ebt_filter_arp,
121 .check = ebt_arp_check,
Bart De Schuymer02fd5952003-03-03 13:01:37 +0000122 .me = THIS_MODULE,
Bart De Schuymerff871722003-06-03 18:47:33 +0000123 .version = VERSIONIZE(1,0),
Bart De Schuymere5ed2162002-09-16 20:02:51 +0000124};
125
126static int __init init(void)
127{
128 return ebt_register_match(&filter_arp);
129}
130
131static void __exit fini(void)
132{
133 ebt_unregister_match(&filter_arp);
134}
135
136module_init(init);
137module_exit(fini);
138MODULE_LICENSE("GPL");