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