Merge branch 'fbdev-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / net / netfilter / ipset / ip_set_hash_netport.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:net,port 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
20 #include <linux/netfilter.h>
21 #include <linux/netfilter/ipset/pfxlen.h>
22 #include <linux/netfilter/ipset/ip_set.h>
23 #include <linux/netfilter/ipset/ip_set_timeout.h>
24 #include <linux/netfilter/ipset/ip_set_getport.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:net,port type of IP sets");
30 MODULE_ALIAS("ip_set_hash:net,port");
31
32 /* Type specific function prefix */
33 #define TYPE            hash_netport
34
35 static bool
36 hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
37
38 #define hash_netport4_same_set  hash_netport_same_set
39 #define hash_netport6_same_set  hash_netport_same_set
40
41 /* The type variant functions: IPv4 */
42
43 /* Member elements without timeout */
44 struct hash_netport4_elem {
45         __be32 ip;
46         __be16 port;
47         u8 proto;
48         u8 cidr;
49 };
50
51 /* Member elements with timeout support */
52 struct hash_netport4_telem {
53         __be32 ip;
54         __be16 port;
55         u8 proto;
56         u8 cidr;
57         unsigned long timeout;
58 };
59
60 static inline bool
61 hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
62                          const struct hash_netport4_elem *ip2)
63 {
64         return ip1->ip == ip2->ip &&
65                ip1->port == ip2->port &&
66                ip1->proto == ip2->proto &&
67                ip1->cidr == ip2->cidr;
68 }
69
70 static inline bool
71 hash_netport4_data_isnull(const struct hash_netport4_elem *elem)
72 {
73         return elem->proto == 0;
74 }
75
76 static inline void
77 hash_netport4_data_copy(struct hash_netport4_elem *dst,
78                         const struct hash_netport4_elem *src)
79 {
80         dst->ip = src->ip;
81         dst->port = src->port;
82         dst->proto = src->proto;
83         dst->cidr = src->cidr;
84 }
85
86 static inline void
87 hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
88 {
89         elem->ip &= ip_set_netmask(cidr);
90         elem->cidr = cidr;
91 }
92
93 static inline void
94 hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
95 {
96         elem->proto = 0;
97 }
98
99 static bool
100 hash_netport4_data_list(struct sk_buff *skb,
101                         const struct hash_netport4_elem *data)
102 {
103         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
104         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
105         NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
106         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
107         return 0;
108
109 nla_put_failure:
110         return 1;
111 }
112
113 static bool
114 hash_netport4_data_tlist(struct sk_buff *skb,
115                          const struct hash_netport4_elem *data)
116 {
117         const struct hash_netport4_telem *tdata =
118                 (const struct hash_netport4_telem *)data;
119
120         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
121         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
122         NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
123         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
124         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
125                       htonl(ip_set_timeout_get(tdata->timeout)));
126
127         return 0;
128
129 nla_put_failure:
130         return 1;
131 }
132
133 #define IP_SET_HASH_WITH_PROTO
134 #define IP_SET_HASH_WITH_NETS
135
136 #define PF              4
137 #define HOST_MASK       32
138 #include <linux/netfilter/ipset/ip_set_ahash.h>
139
140 static int
141 hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
142                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
143 {
144         const struct ip_set_hash *h = set->data;
145         ipset_adtfn adtfn = set->variant->adt[adt];
146         struct hash_netport4_elem data = {
147                 .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
148         };
149
150         if (data.cidr == 0)
151                 return -EINVAL;
152         if (adt == IPSET_TEST)
153                 data.cidr = HOST_MASK;
154
155         if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
156                                  &data.port, &data.proto))
157                 return -EINVAL;
158
159         ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
160         data.ip &= ip_set_netmask(data.cidr);
161
162         return adtfn(set, &data, h->timeout);
163 }
164
165 static int
166 hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
167                    enum ipset_adt adt, u32 *lineno, u32 flags)
168 {
169         const struct ip_set_hash *h = set->data;
170         ipset_adtfn adtfn = set->variant->adt[adt];
171         struct hash_netport4_elem data = { .cidr = HOST_MASK };
172         u32 port, port_to;
173         u32 timeout = h->timeout;
174         bool with_ports = false;
175         int ret;
176
177         if (unlikely(!tb[IPSET_ATTR_IP] ||
178                      !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
179                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
180                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
181                 return -IPSET_ERR_PROTOCOL;
182
183         if (tb[IPSET_ATTR_LINENO])
184                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
185
186         ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
187         if (ret)
188                 return ret;
189
190         if (tb[IPSET_ATTR_CIDR])
191                 data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
192         if (!data.cidr)
193                 return -IPSET_ERR_INVALID_CIDR;
194         data.ip &= ip_set_netmask(data.cidr);
195
196         if (tb[IPSET_ATTR_PORT])
197                 data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
198         else
199                 return -IPSET_ERR_PROTOCOL;
200
201         if (tb[IPSET_ATTR_PROTO]) {
202                 data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
203                 with_ports = ip_set_proto_with_ports(data.proto);
204
205                 if (data.proto == 0)
206                         return -IPSET_ERR_INVALID_PROTO;
207         } else
208                 return -IPSET_ERR_MISSING_PROTO;
209
210         if (!(with_ports || data.proto == IPPROTO_ICMP))
211                 data.port = 0;
212
213         if (tb[IPSET_ATTR_TIMEOUT]) {
214                 if (!with_timeout(h->timeout))
215                         return -IPSET_ERR_TIMEOUT;
216                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
217         }
218
219         if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
220                 ret = adtfn(set, &data, timeout);
221                 return ip_set_eexist(ret, flags) ? 0 : ret;
222         }
223
224         port = ntohs(data.port);
225         port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
226         if (port > port_to)
227                 swap(port, port_to);
228
229         for (; port <= port_to; port++) {
230                 data.port = htons(port);
231                 ret = adtfn(set, &data, timeout);
232
233                 if (ret && !ip_set_eexist(ret, flags))
234                         return ret;
235                 else
236                         ret = 0;
237         }
238         return ret;
239 }
240
241 static bool
242 hash_netport_same_set(const struct ip_set *a, const struct ip_set *b)
243 {
244         const struct ip_set_hash *x = a->data;
245         const struct ip_set_hash *y = b->data;
246
247         /* Resizing changes htable_bits, so we ignore it */
248         return x->maxelem == y->maxelem &&
249                x->timeout == y->timeout;
250 }
251
252 /* The type variant functions: IPv6 */
253
254 struct hash_netport6_elem {
255         union nf_inet_addr ip;
256         __be16 port;
257         u8 proto;
258         u8 cidr;
259 };
260
261 struct hash_netport6_telem {
262         union nf_inet_addr ip;
263         __be16 port;
264         u8 proto;
265         u8 cidr;
266         unsigned long timeout;
267 };
268
269 static inline bool
270 hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
271                          const struct hash_netport6_elem *ip2)
272 {
273         return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
274                ip1->port == ip2->port &&
275                ip1->proto == ip2->proto &&
276                ip1->cidr == ip2->cidr;
277 }
278
279 static inline bool
280 hash_netport6_data_isnull(const struct hash_netport6_elem *elem)
281 {
282         return elem->proto == 0;
283 }
284
285 static inline void
286 hash_netport6_data_copy(struct hash_netport6_elem *dst,
287                         const struct hash_netport6_elem *src)
288 {
289         memcpy(dst, src, sizeof(*dst));
290 }
291
292 static inline void
293 hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
294 {
295         elem->proto = 0;
296 }
297
298 static inline void
299 ip6_netmask(union nf_inet_addr *ip, u8 prefix)
300 {
301         ip->ip6[0] &= ip_set_netmask6(prefix)[0];
302         ip->ip6[1] &= ip_set_netmask6(prefix)[1];
303         ip->ip6[2] &= ip_set_netmask6(prefix)[2];
304         ip->ip6[3] &= ip_set_netmask6(prefix)[3];
305 }
306
307 static inline void
308 hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
309 {
310         ip6_netmask(&elem->ip, cidr);
311         elem->cidr = cidr;
312 }
313
314 static bool
315 hash_netport6_data_list(struct sk_buff *skb,
316                         const struct hash_netport6_elem *data)
317 {
318         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
319         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
320         NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
321         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
322         return 0;
323
324 nla_put_failure:
325         return 1;
326 }
327
328 static bool
329 hash_netport6_data_tlist(struct sk_buff *skb,
330                          const struct hash_netport6_elem *data)
331 {
332         const struct hash_netport6_telem *e =
333                 (const struct hash_netport6_telem *)data;
334
335         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
336         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
337         NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
338         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
339         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
340                       htonl(ip_set_timeout_get(e->timeout)));
341         return 0;
342
343 nla_put_failure:
344         return 1;
345 }
346
347 #undef PF
348 #undef HOST_MASK
349
350 #define PF              6
351 #define HOST_MASK       128
352 #include <linux/netfilter/ipset/ip_set_ahash.h>
353
354 static int
355 hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
356                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
357 {
358         const struct ip_set_hash *h = set->data;
359         ipset_adtfn adtfn = set->variant->adt[adt];
360         struct hash_netport6_elem data = {
361                 .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
362         };
363
364         if (data.cidr == 0)
365                 return -EINVAL;
366         if (adt == IPSET_TEST)
367                 data.cidr = HOST_MASK;
368
369         if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
370                                  &data.port, &data.proto))
371                 return -EINVAL;
372
373         ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
374         ip6_netmask(&data.ip, data.cidr);
375
376         return adtfn(set, &data, h->timeout);
377 }
378
379 static int
380 hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
381                    enum ipset_adt adt, u32 *lineno, u32 flags)
382 {
383         const struct ip_set_hash *h = set->data;
384         ipset_adtfn adtfn = set->variant->adt[adt];
385         struct hash_netport6_elem data = { .cidr = HOST_MASK };
386         u32 port, port_to;
387         u32 timeout = h->timeout;
388         bool with_ports = false;
389         int ret;
390
391         if (unlikely(!tb[IPSET_ATTR_IP] ||
392                      !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
393                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
394                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
395                 return -IPSET_ERR_PROTOCOL;
396
397         if (tb[IPSET_ATTR_LINENO])
398                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
399
400         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
401         if (ret)
402                 return ret;
403
404         if (tb[IPSET_ATTR_CIDR])
405                 data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
406         if (!data.cidr)
407                 return -IPSET_ERR_INVALID_CIDR;
408         ip6_netmask(&data.ip, data.cidr);
409
410         if (tb[IPSET_ATTR_PORT])
411                 data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
412         else
413                 return -IPSET_ERR_PROTOCOL;
414
415         if (tb[IPSET_ATTR_PROTO]) {
416                 data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
417                 with_ports = ip_set_proto_with_ports(data.proto);
418
419                 if (data.proto == 0)
420                         return -IPSET_ERR_INVALID_PROTO;
421         } else
422                 return -IPSET_ERR_MISSING_PROTO;
423
424         if (!(with_ports || data.proto == IPPROTO_ICMPV6))
425                 data.port = 0;
426
427         if (tb[IPSET_ATTR_TIMEOUT]) {
428                 if (!with_timeout(h->timeout))
429                         return -IPSET_ERR_TIMEOUT;
430                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
431         }
432
433         if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
434                 ret = adtfn(set, &data, timeout);
435                 return ip_set_eexist(ret, flags) ? 0 : ret;
436         }
437
438         port = ntohs(data.port);
439         port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
440         if (port > port_to)
441                 swap(port, port_to);
442
443         for (; port <= port_to; port++) {
444                 data.port = htons(port);
445                 ret = adtfn(set, &data, timeout);
446
447                 if (ret && !ip_set_eexist(ret, flags))
448                         return ret;
449                 else
450                         ret = 0;
451         }
452         return ret;
453 }
454
455 /* Create hash:ip type of sets */
456
457 static int
458 hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
459 {
460         struct ip_set_hash *h;
461         u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
462         u8 hbits;
463
464         if (!(set->family == AF_INET || set->family == AF_INET6))
465                 return -IPSET_ERR_INVALID_FAMILY;
466
467         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
468                      !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
469                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
470                 return -IPSET_ERR_PROTOCOL;
471
472         if (tb[IPSET_ATTR_HASHSIZE]) {
473                 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
474                 if (hashsize < IPSET_MIMINAL_HASHSIZE)
475                         hashsize = IPSET_MIMINAL_HASHSIZE;
476         }
477
478         if (tb[IPSET_ATTR_MAXELEM])
479                 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
480
481         h = kzalloc(sizeof(*h)
482                     + sizeof(struct ip_set_hash_nets)
483                       * (set->family == AF_INET ? 32 : 128), GFP_KERNEL);
484         if (!h)
485                 return -ENOMEM;
486
487         h->maxelem = maxelem;
488         get_random_bytes(&h->initval, sizeof(h->initval));
489         h->timeout = IPSET_NO_TIMEOUT;
490
491         hbits = htable_bits(hashsize);
492         h->table = ip_set_alloc(
493                         sizeof(struct htable)
494                         + jhash_size(hbits) * sizeof(struct hbucket));
495         if (!h->table) {
496                 kfree(h);
497                 return -ENOMEM;
498         }
499         h->table->htable_bits = hbits;
500
501         set->data = h;
502
503         if (tb[IPSET_ATTR_TIMEOUT]) {
504                 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
505
506                 set->variant = set->family == AF_INET
507                         ? &hash_netport4_tvariant : &hash_netport6_tvariant;
508
509                 if (set->family == AF_INET)
510                         hash_netport4_gc_init(set);
511                 else
512                         hash_netport6_gc_init(set);
513         } else {
514                 set->variant = set->family == AF_INET
515                         ? &hash_netport4_variant : &hash_netport6_variant;
516         }
517
518         pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
519                  set->name, jhash_size(h->table->htable_bits),
520                  h->table->htable_bits, h->maxelem, set->data, h->table);
521
522         return 0;
523 }
524
525 static struct ip_set_type hash_netport_type __read_mostly = {
526         .name           = "hash:net,port",
527         .protocol       = IPSET_PROTOCOL,
528         .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
529         .dimension      = IPSET_DIM_TWO,
530         .family         = AF_UNSPEC,
531         .revision       = 1,
532         .create         = hash_netport_create,
533         .create_policy  = {
534                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
535                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
536                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
537                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
538                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
539                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
540         },
541         .adt_policy     = {
542                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
543                 [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
544                 [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
545                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
546                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
547                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
548                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
549         },
550         .me             = THIS_MODULE,
551 };
552
553 static int __init
554 hash_netport_init(void)
555 {
556         return ip_set_type_register(&hash_netport_type);
557 }
558
559 static void __exit
560 hash_netport_fini(void)
561 {
562         ip_set_type_unregister(&hash_netport_type);
563 }
564
565 module_init(hash_netport_init);
566 module_exit(hash_netport_fini);