ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / net / bridge / netfilter / ebt_arp.c
1 /*
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  */
11
12 #include <linux/netfilter_bridge/ebtables.h>
13 #include <linux/netfilter_bridge/ebt_arp.h>
14 #include <linux/if_arp.h>
15 #include <linux/if_ether.h>
16 #include <linux/module.h>
17
18 static 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;
22         struct arphdr arph;
23
24         if (skb_copy_bits(skb, 0, &arph, sizeof(arph)))
25                 return EBT_NOMATCH;
26         if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
27            arph.ar_op, EBT_ARP_OPCODE))
28                 return EBT_NOMATCH;
29         if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
30            arph.ar_hrd, EBT_ARP_HTYPE))
31                 return EBT_NOMATCH;
32         if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
33            arph.ar_pro, EBT_ARP_PTYPE))
34                 return EBT_NOMATCH;
35
36         if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
37                 uint32_t addr;
38
39                 /* IPv4 addresses are always 4 bytes */
40                 if (arph.ar_pln != sizeof(uint32_t))
41                         return EBT_NOMATCH;
42                 if (info->bitmask & EBT_ARP_SRC_IP) {
43                         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),
47                            EBT_ARP_SRC_IP))
48                                 return EBT_NOMATCH;
49                 }
50
51                 if (info->bitmask & EBT_ARP_DST_IP) {
52                         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),
57                            EBT_ARP_DST_IP))
58                                 return EBT_NOMATCH;
59                 }
60         }
61
62         if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
63                 unsigned char mac[ETH_ALEN];
64                 uint8_t verdict, i;
65
66                 /* MAC addresses are 6 bytes */
67                 if (arph.ar_hln != ETH_ALEN)
68                         return EBT_NOMATCH;
69                 if (info->bitmask & EBT_ARP_SRC_MAC) {
70                         if (skb_copy_bits(skb, sizeof(struct arphdr), &mac,
71                             ETH_ALEN))
72                                 return EBT_NOMATCH;
73                         verdict = 0;
74                         for (i = 0; i < 6; i++)
75                                 verdict |= (mac[i] ^ info->smaddr[i]) &
76                                        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) {
82                         if (skb_copy_bits(skb, sizeof(struct arphdr) +
83                             arph.ar_hln + arph.ar_pln, &mac, ETH_ALEN))
84                                 return EBT_NOMATCH;
85                         verdict = 0;
86                         for (i = 0; i < 6; i++)
87                                 verdict |= (mac[i] ^ info->dmaddr[i]) &
88                                         info->dmmsk[i];
89                         if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
90                                 return EBT_NOMATCH;
91                 }
92         }
93
94         return EBT_MATCH;
95 }
96
97 static int ebt_arp_check(const char *tablename, unsigned int hookmask,
98    const struct ebt_entry *e, void *data, unsigned int datalen)
99 {
100         struct ebt_arp_info *info = (struct ebt_arp_info *)data;
101
102         if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
103                 return -EINVAL;
104         if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
105            e->ethproto != __constant_htons(ETH_P_RARP)) ||
106            e->invflags & EBT_IPROTO)
107                 return -EINVAL;
108         if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
109                 return -EINVAL;
110         return 0;
111 }
112
113 static struct ebt_match filter_arp =
114 {
115         .name           = EBT_ARP_MATCH,
116         .match          = ebt_filter_arp,
117         .check          = ebt_arp_check,
118         .me             = THIS_MODULE,
119 };
120
121 static int __init init(void)
122 {
123         return ebt_register_match(&filter_arp);
124 }
125
126 static void __exit fini(void)
127 {
128         ebt_unregister_match(&filter_arp);
129 }
130
131 module_init(init);
132 module_exit(fini);
133 MODULE_LICENSE("GPL");