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,port,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/random.h>
18 #include <net/netlink.h>
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>
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");
33 /* Type specific function prefix */
34 #define TYPE hash_ipportip
37 hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
39 #define hash_ipportip4_same_set hash_ipportip_same_set
40 #define hash_ipportip6_same_set hash_ipportip_same_set
42 /* The type variant functions: IPv4 */
44 /* Member elements without timeout */
45 struct hash_ipportip4_elem {
53 /* Member elements with timeout support */
54 struct hash_ipportip4_telem {
60 unsigned long timeout;
64 hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
65 const struct hash_ipportip4_elem *ip2,
68 return ip1->ip == ip2->ip &&
69 ip1->ip2 == ip2->ip2 &&
70 ip1->port == ip2->port &&
71 ip1->proto == ip2->proto;
75 hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
77 return elem->proto == 0;
81 hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
82 const struct hash_ipportip4_elem *src)
84 memcpy(dst, src, sizeof(*dst));
88 hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
94 hash_ipportip4_data_list(struct sk_buff *skb,
95 const struct hash_ipportip4_elem *data)
97 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
98 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
99 NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
100 NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
108 hash_ipportip4_data_tlist(struct sk_buff *skb,
109 const struct hash_ipportip4_elem *data)
111 const struct hash_ipportip4_telem *tdata =
112 (const struct hash_ipportip4_telem *)data;
114 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
115 NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
116 NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
117 NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
118 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
119 htonl(ip_set_timeout_get(tdata->timeout)));
129 #include <linux/netfilter/ipset/ip_set_ahash.h>
132 hash_ipportip4_data_next(struct ip_set_hash *h,
133 const struct hash_ipportip4_elem *d)
135 h->next.ip = ntohl(d->ip);
136 h->next.port = ntohs(d->port);
140 hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
141 const struct xt_action_param *par,
142 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
144 const struct ip_set_hash *h = set->data;
145 ipset_adtfn adtfn = set->variant->adt[adt];
146 struct hash_ipportip4_elem data = { };
148 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
149 &data.port, &data.proto))
152 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
153 ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
155 return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
159 hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
160 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
162 const struct ip_set_hash *h = set->data;
163 ipset_adtfn adtfn = set->variant->adt[adt];
164 struct hash_ipportip4_elem data = { };
165 u32 ip, ip_to = 0, p = 0, port, port_to;
166 u32 timeout = h->timeout;
167 bool with_ports = false;
170 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
171 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
172 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
173 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
174 return -IPSET_ERR_PROTOCOL;
176 if (tb[IPSET_ATTR_LINENO])
177 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
179 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
183 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
187 if (tb[IPSET_ATTR_PORT])
188 data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
190 return -IPSET_ERR_PROTOCOL;
192 if (tb[IPSET_ATTR_PROTO]) {
193 data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
194 with_ports = ip_set_proto_with_ports(data.proto);
197 return -IPSET_ERR_INVALID_PROTO;
199 return -IPSET_ERR_MISSING_PROTO;
201 if (!(with_ports || data.proto == IPPROTO_ICMP))
204 if (tb[IPSET_ATTR_TIMEOUT]) {
205 if (!with_timeout(h->timeout))
206 return -IPSET_ERR_TIMEOUT;
207 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
210 if (adt == IPSET_TEST ||
211 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
212 tb[IPSET_ATTR_PORT_TO])) {
213 ret = adtfn(set, &data, timeout, flags);
214 return ip_set_eexist(ret, flags) ? 0 : ret;
218 if (tb[IPSET_ATTR_IP_TO]) {
219 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
224 } else if (tb[IPSET_ATTR_CIDR]) {
225 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
228 return -IPSET_ERR_INVALID_CIDR;
229 ip_set_mask_from_to(ip, ip_to, cidr);
233 port_to = port = ntohs(data.port);
234 if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
235 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
242 for (; !before(ip_to, ip); ip++) {
243 p = retried && ip == h->next.ip ? h->next.port : port;
244 for (; p <= port_to; p++) {
246 data.port = htons(p);
247 ret = adtfn(set, &data, timeout, flags);
249 if (ret && !ip_set_eexist(ret, flags))
259 hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
261 const struct ip_set_hash *x = a->data;
262 const struct ip_set_hash *y = b->data;
264 /* Resizing changes htable_bits, so we ignore it */
265 return x->maxelem == y->maxelem &&
266 x->timeout == y->timeout;
269 /* The type variant functions: IPv6 */
271 struct hash_ipportip6_elem {
272 union nf_inet_addr ip;
273 union nf_inet_addr ip2;
279 struct hash_ipportip6_telem {
280 union nf_inet_addr ip;
281 union nf_inet_addr ip2;
285 unsigned long timeout;
289 hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
290 const struct hash_ipportip6_elem *ip2,
293 return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
294 ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
295 ip1->port == ip2->port &&
296 ip1->proto == ip2->proto;
300 hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
302 return elem->proto == 0;
306 hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
307 const struct hash_ipportip6_elem *src)
309 memcpy(dst, src, sizeof(*dst));
313 hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
319 hash_ipportip6_data_list(struct sk_buff *skb,
320 const struct hash_ipportip6_elem *data)
322 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
323 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
324 NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
325 NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
333 hash_ipportip6_data_tlist(struct sk_buff *skb,
334 const struct hash_ipportip6_elem *data)
336 const struct hash_ipportip6_telem *e =
337 (const struct hash_ipportip6_telem *)data;
339 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
340 NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
341 NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
342 NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
343 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
344 htonl(ip_set_timeout_get(e->timeout)));
355 #define HOST_MASK 128
356 #include <linux/netfilter/ipset/ip_set_ahash.h>
359 hash_ipportip6_data_next(struct ip_set_hash *h,
360 const struct hash_ipportip6_elem *d)
362 h->next.port = ntohs(d->port);
366 hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
367 const struct xt_action_param *par,
368 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
370 const struct ip_set_hash *h = set->data;
371 ipset_adtfn adtfn = set->variant->adt[adt];
372 struct hash_ipportip6_elem data = { };
374 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
375 &data.port, &data.proto))
378 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
379 ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
381 return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
385 hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
386 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
388 const struct ip_set_hash *h = set->data;
389 ipset_adtfn adtfn = set->variant->adt[adt];
390 struct hash_ipportip6_elem data = { };
392 u32 timeout = h->timeout;
393 bool with_ports = false;
396 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
397 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
398 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
399 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
400 tb[IPSET_ATTR_IP_TO] ||
401 tb[IPSET_ATTR_CIDR]))
402 return -IPSET_ERR_PROTOCOL;
404 if (tb[IPSET_ATTR_LINENO])
405 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
407 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
411 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
415 if (tb[IPSET_ATTR_PORT])
416 data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
418 return -IPSET_ERR_PROTOCOL;
420 if (tb[IPSET_ATTR_PROTO]) {
421 data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
422 with_ports = ip_set_proto_with_ports(data.proto);
425 return -IPSET_ERR_INVALID_PROTO;
427 return -IPSET_ERR_MISSING_PROTO;
429 if (!(with_ports || data.proto == IPPROTO_ICMPV6))
432 if (tb[IPSET_ATTR_TIMEOUT]) {
433 if (!with_timeout(h->timeout))
434 return -IPSET_ERR_TIMEOUT;
435 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
438 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
439 ret = adtfn(set, &data, timeout, flags);
440 return ip_set_eexist(ret, flags) ? 0 : ret;
443 port = ntohs(data.port);
444 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
450 for (; port <= port_to; port++) {
451 data.port = htons(port);
452 ret = adtfn(set, &data, timeout, flags);
454 if (ret && !ip_set_eexist(ret, flags))
462 /* Create hash:ip type of sets */
465 hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
467 struct ip_set_hash *h;
468 u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
472 if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
473 return -IPSET_ERR_INVALID_FAMILY;
475 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
476 !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
477 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
478 return -IPSET_ERR_PROTOCOL;
480 if (tb[IPSET_ATTR_HASHSIZE]) {
481 hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
482 if (hashsize < IPSET_MIMINAL_HASHSIZE)
483 hashsize = IPSET_MIMINAL_HASHSIZE;
486 if (tb[IPSET_ATTR_MAXELEM])
487 maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
489 h = kzalloc(sizeof(*h), GFP_KERNEL);
493 h->maxelem = maxelem;
494 get_random_bytes(&h->initval, sizeof(h->initval));
495 h->timeout = IPSET_NO_TIMEOUT;
497 hbits = htable_bits(hashsize);
498 hsize = htable_size(hbits);
503 h->table = ip_set_alloc(hsize);
508 h->table->htable_bits = hbits;
512 if (tb[IPSET_ATTR_TIMEOUT]) {
513 h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
515 set->variant = set->family == NFPROTO_IPV4
516 ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
518 if (set->family == NFPROTO_IPV4)
519 hash_ipportip4_gc_init(set);
521 hash_ipportip6_gc_init(set);
523 set->variant = set->family == NFPROTO_IPV4
524 ? &hash_ipportip4_variant : &hash_ipportip6_variant;
527 pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
528 set->name, jhash_size(h->table->htable_bits),
529 h->table->htable_bits, h->maxelem, set->data, h->table);
534 static struct ip_set_type hash_ipportip_type __read_mostly = {
535 .name = "hash:ip,port,ip",
536 .protocol = IPSET_PROTOCOL,
537 .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
538 .dimension = IPSET_DIM_THREE,
539 .family = NFPROTO_UNSPEC,
541 .revision_max = 1, /* SCTP and UDPLITE support added */
542 .create = hash_ipportip_create,
544 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
545 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
546 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
547 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
548 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
551 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
552 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
553 [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
554 [IPSET_ATTR_PORT] = { .type = NLA_U16 },
555 [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
556 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
557 [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
558 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
559 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
565 hash_ipportip_init(void)
567 return ip_set_type_register(&hash_ipportip_type);
571 hash_ipportip_fini(void)
573 ip_set_type_unregister(&hash_ipportip_type);
576 module_init(hash_ipportip_init);
577 module_exit(hash_ipportip_fini);