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