]> Pileus Git - ~andy/linux/blob - net/netfilter/ipset/ip_set_hash_ip.c
Merge tag 'for-linus-20120706' of git://git.infradead.org/linux-mtd
[~andy/linux] / net / netfilter / ipset / ip_set_hash_ip.c
1 /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation.
6  */
7
8 /* Kernel module implementing an IP set type: the hash:ip type */
9
10 #include <linux/jhash.h>
11 #include <linux/module.h>
12 #include <linux/ip.h>
13 #include <linux/skbuff.h>
14 #include <linux/errno.h>
15 #include <linux/random.h>
16 #include <net/ip.h>
17 #include <net/ipv6.h>
18 #include <net/netlink.h>
19 #include <net/tcp.h>
20
21 #include <linux/netfilter.h>
22 #include <linux/netfilter/ipset/pfxlen.h>
23 #include <linux/netfilter/ipset/ip_set.h>
24 #include <linux/netfilter/ipset/ip_set_timeout.h>
25 #include <linux/netfilter/ipset/ip_set_hash.h>
26
27 MODULE_LICENSE("GPL");
28 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
29 MODULE_DESCRIPTION("hash:ip type of IP sets");
30 MODULE_ALIAS("ip_set_hash:ip");
31
32 /* Type specific function prefix */
33 #define TYPE            hash_ip
34
35 static bool
36 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
37
38 #define hash_ip4_same_set       hash_ip_same_set
39 #define hash_ip6_same_set       hash_ip_same_set
40
41 /* The type variant functions: IPv4 */
42
43 /* Member elements without timeout */
44 struct hash_ip4_elem {
45         __be32 ip;
46 };
47
48 /* Member elements with timeout support */
49 struct hash_ip4_telem {
50         __be32 ip;
51         unsigned long timeout;
52 };
53
54 static inline bool
55 hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
56                     const struct hash_ip4_elem *ip2,
57                     u32 *multi)
58 {
59         return ip1->ip == ip2->ip;
60 }
61
62 static inline bool
63 hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
64 {
65         return elem->ip == 0;
66 }
67
68 static inline void
69 hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
70 {
71         dst->ip = src->ip;
72 }
73
74 /* Zero valued IP addresses cannot be stored */
75 static inline void
76 hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
77 {
78         elem->ip = 0;
79 }
80
81 static inline bool
82 hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
83 {
84         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip))
85                 goto nla_put_failure;
86         return 0;
87
88 nla_put_failure:
89         return 1;
90 }
91
92 static bool
93 hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
94 {
95         const struct hash_ip4_telem *tdata =
96                 (const struct hash_ip4_telem *)data;
97
98         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
99             nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
100                           htonl(ip_set_timeout_get(tdata->timeout))))
101                 goto nla_put_failure;
102
103         return 0;
104
105 nla_put_failure:
106         return 1;
107 }
108
109 #define IP_SET_HASH_WITH_NETMASK
110 #define PF              4
111 #define HOST_MASK       32
112 #include <linux/netfilter/ipset/ip_set_ahash.h>
113
114 static inline void
115 hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
116 {
117         h->next.ip = ntohl(d->ip);
118 }
119
120 static int
121 hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
122               const struct xt_action_param *par,
123               enum ipset_adt adt, const struct ip_set_adt_opt *opt)
124 {
125         const struct ip_set_hash *h = set->data;
126         ipset_adtfn adtfn = set->variant->adt[adt];
127         __be32 ip;
128
129         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
130         ip &= ip_set_netmask(h->netmask);
131         if (ip == 0)
132                 return -EINVAL;
133
134         return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
135 }
136
137 static int
138 hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
139               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
140 {
141         const struct ip_set_hash *h = set->data;
142         ipset_adtfn adtfn = set->variant->adt[adt];
143         u32 ip, ip_to, hosts, timeout = h->timeout;
144         __be32 nip;
145         int ret = 0;
146
147         if (unlikely(!tb[IPSET_ATTR_IP] ||
148                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
149                 return -IPSET_ERR_PROTOCOL;
150
151         if (tb[IPSET_ATTR_LINENO])
152                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
153
154         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
155         if (ret)
156                 return ret;
157
158         ip &= ip_set_hostmask(h->netmask);
159
160         if (tb[IPSET_ATTR_TIMEOUT]) {
161                 if (!with_timeout(h->timeout))
162                         return -IPSET_ERR_TIMEOUT;
163                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
164         }
165
166         if (adt == IPSET_TEST) {
167                 nip = htonl(ip);
168                 if (nip == 0)
169                         return -IPSET_ERR_HASH_ELEM;
170                 return adtfn(set, &nip, timeout, flags);
171         }
172
173         if (tb[IPSET_ATTR_IP_TO]) {
174                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
175                 if (ret)
176                         return ret;
177                 if (ip > ip_to)
178                         swap(ip, ip_to);
179         } else if (tb[IPSET_ATTR_CIDR]) {
180                 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
181
182                 if (cidr > 32)
183                         return -IPSET_ERR_INVALID_CIDR;
184                 ip_set_mask_from_to(ip, ip_to, cidr);
185         } else
186                 ip_to = ip;
187
188         hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
189
190         if (retried)
191                 ip = h->next.ip;
192         for (; !before(ip_to, ip); ip += hosts) {
193                 nip = htonl(ip);
194                 if (nip == 0)
195                         return -IPSET_ERR_HASH_ELEM;
196                 ret = adtfn(set, &nip, timeout, flags);
197
198                 if (ret && !ip_set_eexist(ret, flags))
199                         return ret;
200                 else
201                         ret = 0;
202         }
203         return ret;
204 }
205
206 static bool
207 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
208 {
209         const struct ip_set_hash *x = a->data;
210         const struct ip_set_hash *y = b->data;
211
212         /* Resizing changes htable_bits, so we ignore it */
213         return x->maxelem == y->maxelem &&
214                x->timeout == y->timeout &&
215                x->netmask == y->netmask;
216 }
217
218 /* The type variant functions: IPv6 */
219
220 struct hash_ip6_elem {
221         union nf_inet_addr ip;
222 };
223
224 struct hash_ip6_telem {
225         union nf_inet_addr ip;
226         unsigned long timeout;
227 };
228
229 static inline bool
230 hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
231                     const struct hash_ip6_elem *ip2,
232                     u32 *multi)
233 {
234         return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
235 }
236
237 static inline bool
238 hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
239 {
240         return ipv6_addr_any(&elem->ip.in6);
241 }
242
243 static inline void
244 hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
245 {
246         dst->ip.in6 = src->ip.in6;
247 }
248
249 static inline void
250 hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
251 {
252         ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
253 }
254
255 static inline void
256 ip6_netmask(union nf_inet_addr *ip, u8 prefix)
257 {
258         ip->ip6[0] &= ip_set_netmask6(prefix)[0];
259         ip->ip6[1] &= ip_set_netmask6(prefix)[1];
260         ip->ip6[2] &= ip_set_netmask6(prefix)[2];
261         ip->ip6[3] &= ip_set_netmask6(prefix)[3];
262 }
263
264 static bool
265 hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
266 {
267         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6))
268                 goto nla_put_failure;
269         return 0;
270
271 nla_put_failure:
272         return 1;
273 }
274
275 static bool
276 hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
277 {
278         const struct hash_ip6_telem *e =
279                 (const struct hash_ip6_telem *)data;
280
281         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
282             nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
283                           htonl(ip_set_timeout_get(e->timeout))))
284                 goto nla_put_failure;
285         return 0;
286
287 nla_put_failure:
288         return 1;
289 }
290
291 #undef PF
292 #undef HOST_MASK
293
294 #define PF              6
295 #define HOST_MASK       128
296 #include <linux/netfilter/ipset/ip_set_ahash.h>
297
298 static inline void
299 hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
300 {
301 }
302
303 static int
304 hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
305               const struct xt_action_param *par,
306               enum ipset_adt adt, const struct ip_set_adt_opt *opt)
307 {
308         const struct ip_set_hash *h = set->data;
309         ipset_adtfn adtfn = set->variant->adt[adt];
310         union nf_inet_addr ip;
311
312         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
313         ip6_netmask(&ip, h->netmask);
314         if (ipv6_addr_any(&ip.in6))
315                 return -EINVAL;
316
317         return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
318 }
319
320 static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
321         [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
322         [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
323         [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
324 };
325
326 static int
327 hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
328               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
329 {
330         const struct ip_set_hash *h = set->data;
331         ipset_adtfn adtfn = set->variant->adt[adt];
332         union nf_inet_addr ip;
333         u32 timeout = h->timeout;
334         int ret;
335
336         if (unlikely(!tb[IPSET_ATTR_IP] ||
337                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
338                      tb[IPSET_ATTR_IP_TO] ||
339                      tb[IPSET_ATTR_CIDR]))
340                 return -IPSET_ERR_PROTOCOL;
341
342         if (tb[IPSET_ATTR_LINENO])
343                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
344
345         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
346         if (ret)
347                 return ret;
348
349         ip6_netmask(&ip, h->netmask);
350         if (ipv6_addr_any(&ip.in6))
351                 return -IPSET_ERR_HASH_ELEM;
352
353         if (tb[IPSET_ATTR_TIMEOUT]) {
354                 if (!with_timeout(h->timeout))
355                         return -IPSET_ERR_TIMEOUT;
356                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
357         }
358
359         ret = adtfn(set, &ip, timeout, flags);
360
361         return ip_set_eexist(ret, flags) ? 0 : ret;
362 }
363
364 /* Create hash:ip type of sets */
365
366 static int
367 hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
368 {
369         u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
370         u8 netmask, hbits;
371         size_t hsize;
372         struct ip_set_hash *h;
373
374         if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
375                 return -IPSET_ERR_INVALID_FAMILY;
376         netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
377         pr_debug("Create set %s with family %s\n",
378                  set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
379
380         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
381                      !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
382                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
383                 return -IPSET_ERR_PROTOCOL;
384
385         if (tb[IPSET_ATTR_HASHSIZE]) {
386                 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
387                 if (hashsize < IPSET_MIMINAL_HASHSIZE)
388                         hashsize = IPSET_MIMINAL_HASHSIZE;
389         }
390
391         if (tb[IPSET_ATTR_MAXELEM])
392                 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
393
394         if (tb[IPSET_ATTR_NETMASK]) {
395                 netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
396
397                 if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
398                     (set->family == NFPROTO_IPV6 && netmask > 128) ||
399                     netmask == 0)
400                         return -IPSET_ERR_INVALID_NETMASK;
401         }
402
403         h = kzalloc(sizeof(*h), GFP_KERNEL);
404         if (!h)
405                 return -ENOMEM;
406
407         h->maxelem = maxelem;
408         h->netmask = netmask;
409         get_random_bytes(&h->initval, sizeof(h->initval));
410         h->timeout = IPSET_NO_TIMEOUT;
411
412         hbits = htable_bits(hashsize);
413         hsize = htable_size(hbits);
414         if (hsize == 0) {
415                 kfree(h);
416                 return -ENOMEM;
417         }
418         h->table = ip_set_alloc(hsize);
419         if (!h->table) {
420                 kfree(h);
421                 return -ENOMEM;
422         }
423         h->table->htable_bits = hbits;
424
425         set->data = h;
426
427         if (tb[IPSET_ATTR_TIMEOUT]) {
428                 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
429
430                 set->variant = set->family == NFPROTO_IPV4
431                         ? &hash_ip4_tvariant : &hash_ip6_tvariant;
432
433                 if (set->family == NFPROTO_IPV4)
434                         hash_ip4_gc_init(set);
435                 else
436                         hash_ip6_gc_init(set);
437         } else {
438                 set->variant = set->family == NFPROTO_IPV4
439                         ? &hash_ip4_variant : &hash_ip6_variant;
440         }
441
442         pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
443                  set->name, jhash_size(h->table->htable_bits),
444                  h->table->htable_bits, h->maxelem, set->data, h->table);
445
446         return 0;
447 }
448
449 static struct ip_set_type hash_ip_type __read_mostly = {
450         .name           = "hash:ip",
451         .protocol       = IPSET_PROTOCOL,
452         .features       = IPSET_TYPE_IP,
453         .dimension      = IPSET_DIM_ONE,
454         .family         = NFPROTO_UNSPEC,
455         .revision_min   = 0,
456         .revision_max   = 0,
457         .create         = hash_ip_create,
458         .create_policy  = {
459                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
460                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
461                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
462                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
463                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
464                 [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
465         },
466         .adt_policy     = {
467                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
468                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
469                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
470                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
471                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
472         },
473         .me             = THIS_MODULE,
474 };
475
476 static int __init
477 hash_ip_init(void)
478 {
479         return ip_set_type_register(&hash_ip_type);
480 }
481
482 static void __exit
483 hash_ip_fini(void)
484 {
485         ip_set_type_unregister(&hash_ip_type);
486 }
487
488 module_init(hash_ip_init);
489 module_exit(hash_ip_fini);