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