]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipset/ip_set_hash_ipport.c
bdeb7160508075f960bacc50786174b88c0c9034
[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 {
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_set_mask_from_to(ip, ip_to, cidr);
220         } else
221                 ip_to = ip;
222
223         port_to = port = ntohs(data.port);
224         if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
225                 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
226                 if (port > port_to)
227                         swap(port, port_to);
228         }
229
230         if (retried)
231                 ip = h->next.ip;
232         for (; !before(ip_to, ip); ip++) {
233                 p = retried && ip == h->next.ip ? h->next.port : port;
234                 for (; p <= port_to; p++) {
235                         data.ip = htonl(ip);
236                         data.port = htons(p);
237                         ret = adtfn(set, &data, timeout, flags);
238
239                         if (ret && !ip_set_eexist(ret, flags))
240                                 return ret;
241                         else
242                                 ret = 0;
243                 }
244         }
245         return ret;
246 }
247
248 static bool
249 hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
250 {
251         const struct ip_set_hash *x = a->data;
252         const struct ip_set_hash *y = b->data;
253
254         /* Resizing changes htable_bits, so we ignore it */
255         return x->maxelem == y->maxelem &&
256                x->timeout == y->timeout;
257 }
258
259 /* The type variant functions: IPv6 */
260
261 struct hash_ipport6_elem {
262         union nf_inet_addr ip;
263         __be16 port;
264         u8 proto;
265         u8 padding;
266 };
267
268 struct hash_ipport6_telem {
269         union nf_inet_addr ip;
270         __be16 port;
271         u8 proto;
272         u8 padding;
273         unsigned long timeout;
274 };
275
276 static inline bool
277 hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
278                         const struct hash_ipport6_elem *ip2)
279 {
280         return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
281                ip1->port == ip2->port &&
282                ip1->proto == ip2->proto;
283 }
284
285 static inline bool
286 hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
287 {
288         return elem->proto == 0;
289 }
290
291 static inline void
292 hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
293                        const struct hash_ipport6_elem *src)
294 {
295         memcpy(dst, src, sizeof(*dst));
296 }
297
298 static inline void
299 hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
300 {
301         elem->proto = 0;
302 }
303
304 static bool
305 hash_ipport6_data_list(struct sk_buff *skb,
306                        const struct hash_ipport6_elem *data)
307 {
308         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
309         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
310         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
311         return 0;
312
313 nla_put_failure:
314         return 1;
315 }
316
317 static bool
318 hash_ipport6_data_tlist(struct sk_buff *skb,
319                         const struct hash_ipport6_elem *data)
320 {
321         const struct hash_ipport6_telem *e =
322                 (const struct hash_ipport6_telem *)data;
323
324         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
325         NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
326         NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
327         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
328                       htonl(ip_set_timeout_get(e->timeout)));
329         return 0;
330
331 nla_put_failure:
332         return 1;
333 }
334
335 #undef PF
336 #undef HOST_MASK
337
338 #define PF              6
339 #define HOST_MASK       128
340 #include <linux/netfilter/ipset/ip_set_ahash.h>
341
342 static inline void
343 hash_ipport6_data_next(struct ip_set_hash *h,
344                        const struct hash_ipport6_elem *d)
345 {
346         h->next.port = ntohs(d->port);
347 }
348
349 static int
350 hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
351                   enum ipset_adt adt, const struct ip_set_adt_opt *opt)
352 {
353         const struct ip_set_hash *h = set->data;
354         ipset_adtfn adtfn = set->variant->adt[adt];
355         struct hash_ipport6_elem data = { };
356
357         if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
358                                  &data.port, &data.proto))
359                 return -EINVAL;
360
361         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
362
363         return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
364 }
365
366 static int
367 hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
368                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
369 {
370         const struct ip_set_hash *h = set->data;
371         ipset_adtfn adtfn = set->variant->adt[adt];
372         struct hash_ipport6_elem data = { };
373         u32 port, port_to;
374         u32 timeout = h->timeout;
375         bool with_ports = false;
376         int ret;
377
378         if (unlikely(!tb[IPSET_ATTR_IP] ||
379                      !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
380                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
381                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
382                      tb[IPSET_ATTR_IP_TO] ||
383                      tb[IPSET_ATTR_CIDR]))
384                 return -IPSET_ERR_PROTOCOL;
385
386         if (tb[IPSET_ATTR_LINENO])
387                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
388
389         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
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, flags);
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         if (retried)
427                 port = h->next.port;
428         for (; port <= port_to; port++) {
429                 data.port = htons(port);
430                 ret = adtfn(set, &data, timeout, flags);
431
432                 if (ret && !ip_set_eexist(ret, flags))
433                         return ret;
434                 else
435                         ret = 0;
436         }
437         return ret;
438 }
439
440 /* Create hash:ip type of sets */
441
442 static int
443 hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
444 {
445         struct ip_set_hash *h;
446         u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
447         u8 hbits;
448
449         if (!(set->family == AF_INET || set->family == AF_INET6))
450                 return -IPSET_ERR_INVALID_FAMILY;
451
452         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
453                      !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
454                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
455                 return -IPSET_ERR_PROTOCOL;
456
457         if (tb[IPSET_ATTR_HASHSIZE]) {
458                 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
459                 if (hashsize < IPSET_MIMINAL_HASHSIZE)
460                         hashsize = IPSET_MIMINAL_HASHSIZE;
461         }
462
463         if (tb[IPSET_ATTR_MAXELEM])
464                 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
465
466         h = kzalloc(sizeof(*h), GFP_KERNEL);
467         if (!h)
468                 return -ENOMEM;
469
470         h->maxelem = maxelem;
471         get_random_bytes(&h->initval, sizeof(h->initval));
472         h->timeout = IPSET_NO_TIMEOUT;
473
474         hbits = htable_bits(hashsize);
475         h->table = ip_set_alloc(
476                         sizeof(struct htable)
477                         + jhash_size(hbits) * sizeof(struct hbucket));
478         if (!h->table) {
479                 kfree(h);
480                 return -ENOMEM;
481         }
482         h->table->htable_bits = hbits;
483
484         set->data = h;
485
486         if (tb[IPSET_ATTR_TIMEOUT]) {
487                 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
488
489                 set->variant = set->family == AF_INET
490                         ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
491
492                 if (set->family == AF_INET)
493                         hash_ipport4_gc_init(set);
494                 else
495                         hash_ipport6_gc_init(set);
496         } else {
497                 set->variant = set->family == AF_INET
498                         ? &hash_ipport4_variant : &hash_ipport6_variant;
499         }
500
501         pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
502                  set->name, jhash_size(h->table->htable_bits),
503                  h->table->htable_bits, h->maxelem, set->data, h->table);
504
505         return 0;
506 }
507
508 static struct ip_set_type hash_ipport_type __read_mostly = {
509         .name           = "hash:ip,port",
510         .protocol       = IPSET_PROTOCOL,
511         .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
512         .dimension      = IPSET_DIM_TWO,
513         .family         = AF_UNSPEC,
514         .revision_min   = 0,
515         .revision_max   = 1,    /* SCTP and UDPLITE support added */
516         .create         = hash_ipport_create,
517         .create_policy  = {
518                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
519                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
520                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
521                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
522                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
523                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
524         },
525         .adt_policy     = {
526                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
527                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
528                 [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
529                 [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
530                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
531                 [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
532                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
533                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
534         },
535         .me             = THIS_MODULE,
536 };
537
538 static int __init
539 hash_ipport_init(void)
540 {
541         return ip_set_type_register(&hash_ipport_type);
542 }
543
544 static void __exit
545 hash_ipport_fini(void)
546 {
547         ip_set_type_unregister(&hash_ipport_type);
548 }
549
550 module_init(hash_ipport_init);
551 module_exit(hash_ipport_fini);