1 /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
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.
8 /* Kernel module implementing an IP set type: the hash:ip type */
10 #include <linux/jhash.h>
11 #include <linux/module.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>
21 #include <net/netlink.h>
24 #include <linux/netfilter.h>
25 #include <linux/netfilter/ipset/pfxlen.h>
26 #include <linux/netfilter/ipset/ip_set.h>
27 #include <linux/netfilter/ipset/ip_set_timeout.h>
28 #include <linux/netfilter/ipset/ip_set_hash.h>
30 MODULE_LICENSE("GPL");
31 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
32 MODULE_DESCRIPTION("hash:ip type of IP sets");
33 MODULE_ALIAS("ip_set_hash:ip");
35 /* Type specific function prefix */
39 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
41 #define hash_ip4_same_set hash_ip_same_set
42 #define hash_ip6_same_set hash_ip_same_set
44 /* The type variant functions: IPv4 */
46 /* Member elements without timeout */
47 struct hash_ip4_elem {
51 /* Member elements with timeout support */
52 struct hash_ip4_telem {
54 unsigned long timeout;
58 hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
59 const struct hash_ip4_elem *ip2)
61 return ip1->ip == ip2->ip;
65 hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
71 hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
76 /* Zero valued IP addresses cannot be stored */
78 hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
84 hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
86 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
94 hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
96 const struct hash_ip4_telem *tdata =
97 (const struct hash_ip4_telem *)data;
99 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
100 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
101 htonl(ip_set_timeout_get(tdata->timeout)));
109 #define IP_SET_HASH_WITH_NETMASK
112 #include <linux/netfilter/ipset/ip_set_ahash.h>
115 hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
116 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
118 const struct ip_set_hash *h = set->data;
119 ipset_adtfn adtfn = set->variant->adt[adt];
122 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
123 ip &= ip_set_netmask(h->netmask);
127 return adtfn(set, &ip, h->timeout);
131 hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
132 enum ipset_adt adt, u32 *lineno, u32 flags)
134 const struct ip_set_hash *h = set->data;
135 ipset_adtfn adtfn = set->variant->adt[adt];
136 u32 ip, ip_to, hosts, timeout = h->timeout;
140 if (unlikely(!tb[IPSET_ATTR_IP] ||
141 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
142 return -IPSET_ERR_PROTOCOL;
144 if (tb[IPSET_ATTR_LINENO])
145 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
147 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
151 ip &= ip_set_hostmask(h->netmask);
153 if (tb[IPSET_ATTR_TIMEOUT]) {
154 if (!with_timeout(h->timeout))
155 return -IPSET_ERR_TIMEOUT;
156 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
159 if (adt == IPSET_TEST) {
162 return -IPSET_ERR_HASH_ELEM;
163 return adtfn(set, &nip, timeout);
166 if (tb[IPSET_ATTR_IP_TO]) {
167 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
172 } else if (tb[IPSET_ATTR_CIDR]) {
173 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
176 return -IPSET_ERR_INVALID_CIDR;
177 ip &= ip_set_hostmask(cidr);
178 ip_to = ip | ~ip_set_hostmask(cidr);
182 hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
184 for (; !before(ip_to, ip); ip += hosts) {
187 return -IPSET_ERR_HASH_ELEM;
188 ret = adtfn(set, &nip, timeout);
190 if (ret && !ip_set_eexist(ret, flags))
199 hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
201 const struct ip_set_hash *x = a->data;
202 const struct ip_set_hash *y = b->data;
204 /* Resizing changes htable_bits, so we ignore it */
205 return x->maxelem == y->maxelem &&
206 x->timeout == y->timeout &&
207 x->netmask == y->netmask;
210 /* The type variant functions: IPv6 */
212 struct hash_ip6_elem {
213 union nf_inet_addr ip;
216 struct hash_ip6_telem {
217 union nf_inet_addr ip;
218 unsigned long timeout;
222 hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
223 const struct hash_ip6_elem *ip2)
225 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
229 hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
231 return ipv6_addr_any(&elem->ip.in6);
235 hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
237 ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
241 hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
243 ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
247 ip6_netmask(union nf_inet_addr *ip, u8 prefix)
249 ip->ip6[0] &= ip_set_netmask6(prefix)[0];
250 ip->ip6[1] &= ip_set_netmask6(prefix)[1];
251 ip->ip6[2] &= ip_set_netmask6(prefix)[2];
252 ip->ip6[3] &= ip_set_netmask6(prefix)[3];
256 hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
258 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
266 hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
268 const struct hash_ip6_telem *e =
269 (const struct hash_ip6_telem *)data;
271 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
272 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
273 htonl(ip_set_timeout_get(e->timeout)));
284 #define HOST_MASK 128
285 #include <linux/netfilter/ipset/ip_set_ahash.h>
288 hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
289 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
291 const struct ip_set_hash *h = set->data;
292 ipset_adtfn adtfn = set->variant->adt[adt];
293 union nf_inet_addr ip;
295 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip.in6);
296 ip6_netmask(&ip, h->netmask);
297 if (ipv6_addr_any(&ip.in6))
300 return adtfn(set, &ip, h->timeout);
303 static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
304 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
305 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
306 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
310 hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
311 enum ipset_adt adt, u32 *lineno, u32 flags)
313 const struct ip_set_hash *h = set->data;
314 ipset_adtfn adtfn = set->variant->adt[adt];
315 union nf_inet_addr ip;
316 u32 timeout = h->timeout;
319 if (unlikely(!tb[IPSET_ATTR_IP] ||
320 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
321 tb[IPSET_ATTR_IP_TO] ||
322 tb[IPSET_ATTR_CIDR]))
323 return -IPSET_ERR_PROTOCOL;
325 if (tb[IPSET_ATTR_LINENO])
326 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
328 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
332 ip6_netmask(&ip, h->netmask);
333 if (ipv6_addr_any(&ip.in6))
334 return -IPSET_ERR_HASH_ELEM;
336 if (tb[IPSET_ATTR_TIMEOUT]) {
337 if (!with_timeout(h->timeout))
338 return -IPSET_ERR_TIMEOUT;
339 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
342 ret = adtfn(set, &ip, timeout);
344 return ip_set_eexist(ret, flags) ? 0 : ret;
347 /* Create hash:ip type of sets */
350 hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
352 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
354 struct ip_set_hash *h;
356 if (!(set->family == AF_INET || set->family == AF_INET6))
357 return -IPSET_ERR_INVALID_FAMILY;
358 netmask = set->family == AF_INET ? 32 : 128;
359 pr_debug("Create set %s with family %s\n",
360 set->name, set->family == AF_INET ? "inet" : "inet6");
362 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
363 !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
364 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
365 return -IPSET_ERR_PROTOCOL;
367 if (tb[IPSET_ATTR_HASHSIZE]) {
368 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
369 if (hashsize < IPSET_MIMINAL_HASHSIZE)
370 hashsize = IPSET_MIMINAL_HASHSIZE;
373 if (tb[IPSET_ATTR_MAXELEM])
374 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
376 if (tb[IPSET_ATTR_NETMASK]) {
377 netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
379 if ((set->family == AF_INET && netmask > 32) ||
380 (set->family == AF_INET6 && netmask > 128) ||
382 return -IPSET_ERR_INVALID_NETMASK;
385 h = kzalloc(sizeof(*h), GFP_KERNEL);
389 h->maxelem = maxelem;
390 h->netmask = netmask;
391 get_random_bytes(&h->initval, sizeof(h->initval));
392 h->timeout = IPSET_NO_TIMEOUT;
394 hbits = htable_bits(hashsize);
395 h->table = ip_set_alloc(
396 sizeof(struct htable)
397 + jhash_size(hbits) * sizeof(struct hbucket));
402 h->table->htable_bits = hbits;
406 if (tb[IPSET_ATTR_TIMEOUT]) {
407 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
409 set->variant = set->family == AF_INET
410 ? &hash_ip4_tvariant : &hash_ip6_tvariant;
412 if (set->family == AF_INET)
413 hash_ip4_gc_init(set);
415 hash_ip6_gc_init(set);
417 set->variant = set->family == AF_INET
418 ? &hash_ip4_variant : &hash_ip6_variant;
421 pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
422 set->name, jhash_size(h->table->htable_bits),
423 h->table->htable_bits, h->maxelem, set->data, h->table);
428 static struct ip_set_type hash_ip_type __read_mostly = {
430 .protocol = IPSET_PROTOCOL,
431 .features = IPSET_TYPE_IP,
432 .dimension = IPSET_DIM_ONE,
435 .create = hash_ip_create,
437 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
438 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
439 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
440 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
441 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
442 [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
445 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
446 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
447 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
448 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
449 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
457 return ip_set_type_register(&hash_ip_type);
463 ip_set_type_unregister(&hash_ip_type);
466 module_init(hash_ip_init);
467 module_exit(hash_ip_fini);