5 * Grzegorz Borowiak <grzes@gnu.univ.gda.pl>
11 #include <linux/netfilter_bridge/ebtables.h>
12 #include <linux/netfilter_bridge/ebt_among.h>
14 #include <linux/if_arp.h>
15 #include <linux/module.h>
17 static int ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
18 const char *mac, uint32_t ip)
20 /* You may be puzzled as to how this code works.
21 * Some tricks were used, refer to
22 * include/linux/netfilter_bridge/ebt_among.h
23 * as there you can find a solution of this mystery.
25 const struct ebt_mac_wormhash_tuple *p;
27 uint32_t cmp[2] = { 0, 0 };
28 int key = (const unsigned char) mac[5];
30 memcpy(((char *) cmp) + 2, mac, 6);
31 start = wh->table[key];
32 limit = wh->table[key + 1];
34 for (i = start; i < limit; i++) {
36 if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
37 if (p->ip == 0 || p->ip == ip) {
43 for (i = start; i < limit; i++) {
45 if (cmp[1] == p->cmp[1] && cmp[0] == p->cmp[0]) {
55 static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
60 for (i = 0; i < 256; i++) {
61 if (wh->table[i] > wh->table[i + 1])
65 if (wh->table[i] > wh->poolsize)
68 if (wh->table[256] > wh->poolsize)
73 static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
75 if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
78 if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
81 } else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
84 if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
85 arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
87 if (skb_copy_bits(skb, sizeof(struct arphdr) +
88 2 * ETH_ALEN + sizeof(uint32_t), addr, sizeof(uint32_t)))
94 static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
96 if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
99 if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
102 } else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
105 if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
106 arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
108 if (skb_copy_bits(skb, sizeof(struct arphdr) +
109 ETH_ALEN, addr, sizeof(uint32_t)))
115 static int ebt_filter_among(const struct sk_buff *skb,
116 const struct net_device *in,
117 const struct net_device *out, const void *data,
118 unsigned int datalen)
120 struct ebt_among_info *info = (struct ebt_among_info *) data;
121 const char *dmac, *smac;
122 const struct ebt_mac_wormhash *wh_dst, *wh_src;
123 uint32_t dip = 0, sip = 0;
125 wh_dst = ebt_among_wh_dst(info);
126 wh_src = ebt_among_wh_src(info);
129 smac = skb->mac.ethernet->h_source;
130 if (get_ip_src(skb, &sip))
132 if (!(info->bitmask & EBT_AMONG_SRC_NEG)) {
133 /* we match only if it contains */
134 if (!ebt_mac_wormhash_contains(wh_src, smac, sip))
137 /* we match only if it DOES NOT contain */
138 if (ebt_mac_wormhash_contains(wh_src, smac, sip))
144 dmac = skb->mac.ethernet->h_dest;
145 if (get_ip_dst(skb, &dip))
147 if (!(info->bitmask & EBT_AMONG_DST_NEG)) {
148 /* we match only if it contains */
149 if (!ebt_mac_wormhash_contains(wh_dst, dmac, dip))
152 /* we match only if it DOES NOT contain */
153 if (ebt_mac_wormhash_contains(wh_dst, dmac, dip))
161 static int ebt_among_check(const char *tablename, unsigned int hookmask,
162 const struct ebt_entry *e, void *data,
163 unsigned int datalen)
165 struct ebt_among_info *info = (struct ebt_among_info *) data;
166 int expected_length = sizeof(struct ebt_among_info);
167 const struct ebt_mac_wormhash *wh_dst, *wh_src;
170 wh_dst = ebt_among_wh_dst(info);
171 wh_src = ebt_among_wh_src(info);
172 expected_length += ebt_mac_wormhash_size(wh_dst);
173 expected_length += ebt_mac_wormhash_size(wh_src);
175 if (datalen != EBT_ALIGN(expected_length)) {
177 "ebtables: among: wrong size: %d"
178 "against expected %d, rounded to %Zd\n",
179 datalen, expected_length,
180 EBT_ALIGN(expected_length));
183 if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
185 "ebtables: among: dst integrity fail: %x\n", -err);
188 if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
190 "ebtables: among: src integrity fail: %x\n", -err);
196 static struct ebt_match filter_among = {
197 .name = EBT_AMONG_MATCH,
198 .match = ebt_filter_among,
199 .check = ebt_among_check,
203 static int __init init(void)
205 return ebt_register_match(&filter_among);
208 static void __exit fini(void)
210 ebt_unregister_match(&filter_among);
215 MODULE_LICENSE("GPL");