401c8a2531dbf471677ba4cb13923fda61e6d7cd
[linux-2.6.git] / net / netfilter / ipset / ip_set_hash_ipportip.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,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_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,ip type of IP sets");
31 MODULE_ALIAS("ip_set_hash:ip,port,ip");
32
33 /* Type specific function prefix */
34 #define TYPE            hash_ipportip
35
36 static bool
37 hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
38
39 #define hash_ipportip4_same_set hash_ipportip_same_set
40 #define hash_ipportip6_same_set hash_ipportip_same_set
41
42 /* The type variant functions: IPv4 */
43
44 /* Member elements without timeout */
45 struct hash_ipportip4_elem {
46         __be32 ip;
47         __be32 ip2;
48         __be16 port;
49         u8 proto;
50         u8 padding;
51 };
52
53 /* Member elements with timeout support */
54 struct hash_ipportip4_telem {
55         __be32 ip;
56         __be32 ip2;
57         __be16 port;
58         u8 proto;
59         u8 padding;
60         unsigned long timeout;
61 };
62
63 static inline bool
64 hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
65                           const struct hash_ipportip4_elem *ip2)
66 {
67         return ip1->ip == ip2->ip &&
68                ip1->ip2 == ip2->ip2 &&
69                ip1->port == ip2->port &&
70                ip1->proto == ip2->proto;
71 }
72
73 static inline bool
74 hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
75 {
76         return elem->proto == 0;
77 }
78
79 static inline void
80 hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
81                          const struct hash_ipportip4_elem *src)
82 {
83         memcpy(dst, src, sizeof(*dst));
84 }
85
86 static inline void
87 hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
88 {
89         elem->proto = 0;
90 }
91
92 static bool
93 hash_ipportip4_data_list(struct sk_buff *skb,
94                        const struct hash_ipportip4_elem *data)
95 {
96         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
97         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
98         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
99         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
100         return 0;
101
102 nla_put_failure:
103         return 1;
104 }
105
106 static bool
107 hash_ipportip4_data_tlist(struct sk_buff *skb,
108                         const struct hash_ipportip4_elem *data)
109 {
110         const struct hash_ipportip4_telem *tdata =
111                 (const struct hash_ipportip4_telem *)data;
112
113         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
114         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
115         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
116         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
117         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
118                       htonl(ip_set_timeout_get(tdata->timeout)));
119
120         return 0;
121
122 nla_put_failure:
123         return 1;
124 }
125
126 #define PF              4
127 #define HOST_MASK       32
128 #include <linux/netfilter/ipset/ip_set_ahash.h>
129
130 static int
131 hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
132                     enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
133 {
134         const struct ip_set_hash *h = set->data;
135         ipset_adtfn adtfn = set->variant->adt[adt];
136         struct hash_ipportip4_elem data = { };
137
138         if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
139                                  &data.port, &data.proto))
140                 return -EINVAL;
141
142         ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
143         ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
144
145         return adtfn(set, &data, h->timeout);
146 }
147
148 static int
149 hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
150                     enum ipset_adt adt, u32 *lineno, u32 flags)
151 {
152         const struct ip_set_hash *h = set->data;
153         ipset_adtfn adtfn = set->variant->adt[adt];
154         struct hash_ipportip4_elem data = { };
155         u32 ip, ip_to, p, port, port_to;
156         u32 timeout = h->timeout;
157         bool with_ports = false;
158         int ret;
159
160         if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
161                      !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
162                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
163                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
164                 return -IPSET_ERR_PROTOCOL;
165
166         if (tb[IPSET_ATTR_LINENO])
167                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
168
169         ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
170         if (ret)
171                 return ret;
172
173         ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
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);
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         for (; !before(ip_to, ip); ip++)
232                 for (p = port; p <= port_to; p++) {
233                         data.ip = htonl(ip);
234                         data.port = htons(p);
235                         ret = adtfn(set, &data, timeout);
236
237                         if (ret && !ip_set_eexist(ret, flags))
238                                 return ret;
239                         else
240                                 ret = 0;
241                 }
242         return ret;
243 }
244
245 static bool
246 hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
247 {
248         const struct ip_set_hash *x = a->data;
249         const struct ip_set_hash *y = b->data;
250
251         /* Resizing changes htable_bits, so we ignore it */
252         return x->maxelem == y->maxelem &&
253                x->timeout == y->timeout;
254 }
255
256 /* The type variant functions: IPv6 */
257
258 struct hash_ipportip6_elem {
259         union nf_inet_addr ip;
260         union nf_inet_addr ip2;
261         __be16 port;
262         u8 proto;
263         u8 padding;
264 };
265
266 struct hash_ipportip6_telem {
267         union nf_inet_addr ip;
268         union nf_inet_addr ip2;
269         __be16 port;
270         u8 proto;
271         u8 padding;
272         unsigned long timeout;
273 };
274
275 static inline bool
276 hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
277                           const struct hash_ipportip6_elem *ip2)
278 {
279         return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
280                ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
281                ip1->port == ip2->port &&
282                ip1->proto == ip2->proto;
283 }
284
285 static inline bool
286 hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
287 {
288         return elem->proto == 0;
289 }
290
291 static inline void
292 hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
293                          const struct hash_ipportip6_elem *src)
294 {
295         memcpy(dst, src, sizeof(*dst));
296 }
297
298 static inline void
299 hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
300 {
301         elem->proto = 0;
302 }
303
304 static bool
305 hash_ipportip6_data_list(struct sk_buff *skb,
306                          const struct hash_ipportip6_elem *data)
307 {
308         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
309         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
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_ipportip6_data_tlist(struct sk_buff *skb,
320                           const struct hash_ipportip6_elem *data)
321 {
322         const struct hash_ipportip6_telem *e =
323                 (const struct hash_ipportip6_telem *)data;
324
325         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
326         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
327         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
328         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
329         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
330                       htonl(ip_set_timeout_get(e->timeout)));
331         return 0;
332
333 nla_put_failure:
334         return 1;
335 }
336
337 #undef PF
338 #undef HOST_MASK
339
340 #define PF              6
341 #define HOST_MASK       128
342 #include <linux/netfilter/ipset/ip_set_ahash.h>
343
344 static int
345 hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
346                     enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
347 {
348         const struct ip_set_hash *h = set->data;
349         ipset_adtfn adtfn = set->variant->adt[adt];
350         struct hash_ipportip6_elem data = { };
351
352         if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
353                                  &data.port, &data.proto))
354                 return -EINVAL;
355
356         ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
357         ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
358
359         return adtfn(set, &data, h->timeout);
360 }
361
362 static int
363 hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
364                     enum ipset_adt adt, u32 *lineno, u32 flags)
365 {
366         const struct ip_set_hash *h = set->data;
367         ipset_adtfn adtfn = set->variant->adt[adt];
368         struct hash_ipportip6_elem data = { };
369         u32 port, port_to;
370         u32 timeout = h->timeout;
371         bool with_ports = false;
372         int ret;
373
374         if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
375                      !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
376                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
377                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
378                      tb[IPSET_ATTR_IP_TO] ||
379                      tb[IPSET_ATTR_CIDR]))
380                 return -IPSET_ERR_PROTOCOL;
381
382         if (tb[IPSET_ATTR_LINENO])
383                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
384
385         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
386         if (ret)
387                 return ret;
388
389         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
390         if (ret)
391                 return ret;
392
393         if (tb[IPSET_ATTR_PORT])
394                 data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
395         else
396                 return -IPSET_ERR_PROTOCOL;
397
398         if (tb[IPSET_ATTR_PROTO]) {
399                 data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
400                 with_ports = ip_set_proto_with_ports(data.proto);
401
402                 if (data.proto == 0)
403                         return -IPSET_ERR_INVALID_PROTO;
404         } else
405                 return -IPSET_ERR_MISSING_PROTO;
406
407         if (!(with_ports || data.proto == IPPROTO_ICMPV6))
408                 data.port = 0;
409
410         if (tb[IPSET_ATTR_TIMEOUT]) {
411                 if (!with_timeout(h->timeout))
412                         return -IPSET_ERR_TIMEOUT;
413                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
414         }
415
416         if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
417                 ret = adtfn(set, &data, timeout);
418                 return ip_set_eexist(ret, flags) ? 0 : ret;
419         }
420
421         port = ntohs(data.port);
422         port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
423         if (port > port_to)
424                 swap(port, port_to);
425
426         for (; port <= port_to; port++) {
427                 data.port = htons(port);
428                 ret = adtfn(set, &data, timeout);
429
430                 if (ret && !ip_set_eexist(ret, flags))
431                         return ret;
432                 else
433                         ret = 0;
434         }
435         return ret;
436 }
437
438 /* Create hash:ip type of sets */
439
440 static int
441 hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
442 {
443         struct ip_set_hash *h;
444         u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
445         u8 hbits;
446
447         if (!(set->family == AF_INET || set->family == AF_INET6))
448                 return -IPSET_ERR_INVALID_FAMILY;
449
450         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
451                      !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
452                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
453                 return -IPSET_ERR_PROTOCOL;
454
455         if (tb[IPSET_ATTR_HASHSIZE]) {
456                 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
457                 if (hashsize < IPSET_MIMINAL_HASHSIZE)
458                         hashsize = IPSET_MIMINAL_HASHSIZE;
459         }
460
461         if (tb[IPSET_ATTR_MAXELEM])
462                 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
463
464         h = kzalloc(sizeof(*h), GFP_KERNEL);
465         if (!h)
466                 return -ENOMEM;
467
468         h->maxelem = maxelem;
469         get_random_bytes(&h->initval, sizeof(h->initval));
470         h->timeout = IPSET_NO_TIMEOUT;
471
472         hbits = htable_bits(hashsize);
473         h->table = ip_set_alloc(
474                         sizeof(struct htable)
475                         + jhash_size(hbits) * sizeof(struct hbucket));
476         if (!h->table) {
477                 kfree(h);
478                 return -ENOMEM;
479         }
480         h->table->htable_bits = hbits;
481
482         set->data = h;
483
484         if (tb[IPSET_ATTR_TIMEOUT]) {
485                 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
486
487                 set->variant = set->family == AF_INET
488                         ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
489
490                 if (set->family == AF_INET)
491                         hash_ipportip4_gc_init(set);
492                 else
493                         hash_ipportip6_gc_init(set);
494         } else {
495                 set->variant = set->family == AF_INET
496                         ? &hash_ipportip4_variant : &hash_ipportip6_variant;
497         }
498
499         pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
500                  set->name, jhash_size(h->table->htable_bits),
501                  h->table->htable_bits, h->maxelem, set->data, h->table);
502
503         return 0;
504 }
505
506 static struct ip_set_type hash_ipportip_type __read_mostly = {
507         .name           = "hash:ip,port,ip",
508         .protocol       = IPSET_PROTOCOL,
509         .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
510         .dimension      = IPSET_DIM_THREE,
511         .family         = AF_UNSPEC,
512         .revision       = 1,
513         .create         = hash_ipportip_create,
514         .create_policy  = {
515                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
516                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
517                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
518                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
519                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
520         },
521         .adt_policy     = {
522                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
523                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
524                 [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
525                 [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
526                 [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
527                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
528                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
529                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
530                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
531         },
532         .me             = THIS_MODULE,
533 };
534
535 static int __init
536 hash_ipportip_init(void)
537 {
538         return ip_set_type_register(&hash_ipportip_type);
539 }
540
541 static void __exit
542 hash_ipportip_fini(void)
543 {
544         ip_set_type_unregister(&hash_ipportip_type);
545 }
546
547 module_init(hash_ipportip_init);
548 module_exit(hash_ipportip_fini);