]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipset/ip_set_hash_ip.c
c99e861ce031cd43aa20f0c58afc6bd1958bbab6
[karo-tx-linux.git] / net / netfilter / ipset / ip_set_hash_ip.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 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_hash.h>
26
27 MODULE_LICENSE("GPL");
28 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
29 MODULE_DESCRIPTION("hash:ip type of IP sets");
30 MODULE_ALIAS("ip_set_hash:ip");
31
32 /* Type specific function prefix */
33 #define TYPE            hash_ip
34
35 static bool
36 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
37
38 #define hash_ip4_same_set       hash_ip_same_set
39 #define hash_ip6_same_set       hash_ip_same_set
40
41 /* The type variant functions: IPv4 */
42
43 /* Member elements without timeout */
44 struct hash_ip4_elem {
45         __be32 ip;
46 };
47
48 /* Member elements with timeout support */
49 struct hash_ip4_telem {
50         __be32 ip;
51         unsigned long timeout;
52 };
53
54 static inline bool
55 hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
56                     const struct hash_ip4_elem *ip2)
57 {
58         return ip1->ip == ip2->ip;
59 }
60
61 static inline bool
62 hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
63 {
64         return elem->ip == 0;
65 }
66
67 static inline void
68 hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
69 {
70         dst->ip = src->ip;
71 }
72
73 /* Zero valued IP addresses cannot be stored */
74 static inline void
75 hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
76 {
77         elem->ip = 0;
78 }
79
80 static inline bool
81 hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
82 {
83         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
84         return 0;
85
86 nla_put_failure:
87         return 1;
88 }
89
90 static bool
91 hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
92 {
93         const struct hash_ip4_telem *tdata =
94                 (const struct hash_ip4_telem *)data;
95
96         NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
97         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
98                       htonl(ip_set_timeout_get(tdata->timeout)));
99
100         return 0;
101
102 nla_put_failure:
103         return 1;
104 }
105
106 #define IP_SET_HASH_WITH_NETMASK
107 #define PF              4
108 #define HOST_MASK       32
109 #include <linux/netfilter/ipset/ip_set_ahash.h>
110
111 static inline void
112 hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
113 {
114         h->next.ip = ntohl(d->ip);
115 }
116
117 static int
118 hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
119               enum ipset_adt adt, const struct ip_set_adt_opt *opt)
120 {
121         const struct ip_set_hash *h = set->data;
122         ipset_adtfn adtfn = set->variant->adt[adt];
123         __be32 ip;
124
125         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
126         ip &= ip_set_netmask(h->netmask);
127         if (ip == 0)
128                 return -EINVAL;
129
130         return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
131 }
132
133 static int
134 hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
135               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
136 {
137         const struct ip_set_hash *h = set->data;
138         ipset_adtfn adtfn = set->variant->adt[adt];
139         u32 ip, ip_to, hosts, timeout = h->timeout;
140         __be32 nip;
141         int ret = 0;
142
143         if (unlikely(!tb[IPSET_ATTR_IP] ||
144                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
145                 return -IPSET_ERR_PROTOCOL;
146
147         if (tb[IPSET_ATTR_LINENO])
148                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
149
150         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
151         if (ret)
152                 return ret;
153
154         ip &= ip_set_hostmask(h->netmask);
155
156         if (tb[IPSET_ATTR_TIMEOUT]) {
157                 if (!with_timeout(h->timeout))
158                         return -IPSET_ERR_TIMEOUT;
159                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
160         }
161
162         if (adt == IPSET_TEST) {
163                 nip = htonl(ip);
164                 if (nip == 0)
165                         return -IPSET_ERR_HASH_ELEM;
166                 return adtfn(set, &nip, timeout, flags);
167         }
168
169         if (tb[IPSET_ATTR_IP_TO]) {
170                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
171                 if (ret)
172                         return ret;
173                 if (ip > ip_to)
174                         swap(ip, ip_to);
175         } else if (tb[IPSET_ATTR_CIDR]) {
176                 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
177
178                 if (cidr > 32)
179                         return -IPSET_ERR_INVALID_CIDR;
180                 ip &= ip_set_hostmask(cidr);
181                 ip_to = ip | ~ip_set_hostmask(cidr);
182         } else
183                 ip_to = ip;
184
185         hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
186
187         if (retried)
188                 ip = h->next.ip;
189         for (; !before(ip_to, ip); ip += hosts) {
190                 nip = htonl(ip);
191                 if (nip == 0)
192                         return -IPSET_ERR_HASH_ELEM;
193                 ret = adtfn(set, &nip, timeout, flags);
194
195                 if (ret && !ip_set_eexist(ret, flags))
196                         return ret;
197                 else
198                         ret = 0;
199         }
200         return ret;
201 }
202
203 static bool
204 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
205 {
206         const struct ip_set_hash *x = a->data;
207         const struct ip_set_hash *y = b->data;
208
209         /* Resizing changes htable_bits, so we ignore it */
210         return x->maxelem == y->maxelem &&
211                x->timeout == y->timeout &&
212                x->netmask == y->netmask;
213 }
214
215 /* The type variant functions: IPv6 */
216
217 struct hash_ip6_elem {
218         union nf_inet_addr ip;
219 };
220
221 struct hash_ip6_telem {
222         union nf_inet_addr ip;
223         unsigned long timeout;
224 };
225
226 static inline bool
227 hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
228                     const struct hash_ip6_elem *ip2)
229 {
230         return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
231 }
232
233 static inline bool
234 hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
235 {
236         return ipv6_addr_any(&elem->ip.in6);
237 }
238
239 static inline void
240 hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
241 {
242         ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
243 }
244
245 static inline void
246 hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
247 {
248         ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
249 }
250
251 static inline void
252 ip6_netmask(union nf_inet_addr *ip, u8 prefix)
253 {
254         ip->ip6[0] &= ip_set_netmask6(prefix)[0];
255         ip->ip6[1] &= ip_set_netmask6(prefix)[1];
256         ip->ip6[2] &= ip_set_netmask6(prefix)[2];
257         ip->ip6[3] &= ip_set_netmask6(prefix)[3];
258 }
259
260 static bool
261 hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
262 {
263         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
264         return 0;
265
266 nla_put_failure:
267         return 1;
268 }
269
270 static bool
271 hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
272 {
273         const struct hash_ip6_telem *e =
274                 (const struct hash_ip6_telem *)data;
275
276         NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
277         NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
278                       htonl(ip_set_timeout_get(e->timeout)));
279         return 0;
280
281 nla_put_failure:
282         return 1;
283 }
284
285 #undef PF
286 #undef HOST_MASK
287
288 #define PF              6
289 #define HOST_MASK       128
290 #include <linux/netfilter/ipset/ip_set_ahash.h>
291
292 static inline void
293 hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
294 {
295 }
296
297 static int
298 hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
299               enum ipset_adt adt, const struct ip_set_adt_opt *opt)
300 {
301         const struct ip_set_hash *h = set->data;
302         ipset_adtfn adtfn = set->variant->adt[adt];
303         union nf_inet_addr ip;
304
305         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
306         ip6_netmask(&ip, h->netmask);
307         if (ipv6_addr_any(&ip.in6))
308                 return -EINVAL;
309
310         return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
311 }
312
313 static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
314         [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
315         [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
316         [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
317 };
318
319 static int
320 hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
321               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
322 {
323         const struct ip_set_hash *h = set->data;
324         ipset_adtfn adtfn = set->variant->adt[adt];
325         union nf_inet_addr ip;
326         u32 timeout = h->timeout;
327         int ret;
328
329         if (unlikely(!tb[IPSET_ATTR_IP] ||
330                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
331                      tb[IPSET_ATTR_IP_TO] ||
332                      tb[IPSET_ATTR_CIDR]))
333                 return -IPSET_ERR_PROTOCOL;
334
335         if (tb[IPSET_ATTR_LINENO])
336                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
337
338         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
339         if (ret)
340                 return ret;
341
342         ip6_netmask(&ip, h->netmask);
343         if (ipv6_addr_any(&ip.in6))
344                 return -IPSET_ERR_HASH_ELEM;
345
346         if (tb[IPSET_ATTR_TIMEOUT]) {
347                 if (!with_timeout(h->timeout))
348                         return -IPSET_ERR_TIMEOUT;
349                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
350         }
351
352         ret = adtfn(set, &ip, timeout, flags);
353
354         return ip_set_eexist(ret, flags) ? 0 : ret;
355 }
356
357 /* Create hash:ip type of sets */
358
359 static int
360 hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
361 {
362         u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
363         u8 netmask, hbits;
364         struct ip_set_hash *h;
365
366         if (!(set->family == AF_INET || set->family == AF_INET6))
367                 return -IPSET_ERR_INVALID_FAMILY;
368         netmask = set->family == AF_INET ? 32 : 128;
369         pr_debug("Create set %s with family %s\n",
370                  set->name, set->family == AF_INET ? "inet" : "inet6");
371
372         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
373                      !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
374                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
375                 return -IPSET_ERR_PROTOCOL;
376
377         if (tb[IPSET_ATTR_HASHSIZE]) {
378                 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
379                 if (hashsize < IPSET_MIMINAL_HASHSIZE)
380                         hashsize = IPSET_MIMINAL_HASHSIZE;
381         }
382
383         if (tb[IPSET_ATTR_MAXELEM])
384                 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
385
386         if (tb[IPSET_ATTR_NETMASK]) {
387                 netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
388
389                 if ((set->family == AF_INET && netmask > 32) ||
390                     (set->family == AF_INET6 && netmask > 128) ||
391                     netmask == 0)
392                         return -IPSET_ERR_INVALID_NETMASK;
393         }
394
395         h = kzalloc(sizeof(*h), GFP_KERNEL);
396         if (!h)
397                 return -ENOMEM;
398
399         h->maxelem = maxelem;
400         h->netmask = netmask;
401         get_random_bytes(&h->initval, sizeof(h->initval));
402         h->timeout = IPSET_NO_TIMEOUT;
403
404         hbits = htable_bits(hashsize);
405         h->table = ip_set_alloc(
406                         sizeof(struct htable)
407                         + jhash_size(hbits) * sizeof(struct hbucket));
408         if (!h->table) {
409                 kfree(h);
410                 return -ENOMEM;
411         }
412         h->table->htable_bits = hbits;
413
414         set->data = h;
415
416         if (tb[IPSET_ATTR_TIMEOUT]) {
417                 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
418
419                 set->variant = set->family == AF_INET
420                         ? &hash_ip4_tvariant : &hash_ip6_tvariant;
421
422                 if (set->family == AF_INET)
423                         hash_ip4_gc_init(set);
424                 else
425                         hash_ip6_gc_init(set);
426         } else {
427                 set->variant = set->family == AF_INET
428                         ? &hash_ip4_variant : &hash_ip6_variant;
429         }
430
431         pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
432                  set->name, jhash_size(h->table->htable_bits),
433                  h->table->htable_bits, h->maxelem, set->data, h->table);
434
435         return 0;
436 }
437
438 static struct ip_set_type hash_ip_type __read_mostly = {
439         .name           = "hash:ip",
440         .protocol       = IPSET_PROTOCOL,
441         .features       = IPSET_TYPE_IP,
442         .dimension      = IPSET_DIM_ONE,
443         .family         = AF_UNSPEC,
444         .revision       = 0,
445         .create         = hash_ip_create,
446         .create_policy  = {
447                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
448                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
449                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
450                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
451                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
452                 [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
453         },
454         .adt_policy     = {
455                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
456                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
457                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
458                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
459                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
460         },
461         .me             = THIS_MODULE,
462 };
463
464 static int __init
465 hash_ip_init(void)
466 {
467         return ip_set_type_register(&hash_ip_type);
468 }
469
470 static void __exit
471 hash_ip_fini(void)
472 {
473         ip_set_type_unregister(&hash_ip_type);
474 }
475
476 module_init(hash_ip_init);
477 module_exit(hash_ip_fini);