1 /* Copyright (C) 2011-2013 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:net,iface 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>
16 #include <linux/rbtree.h>
19 #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_hash.h>
26 #define IPSET_TYPE_REV_MIN 0
27 /* 1 nomatch flag support added */
28 /* 2 /0 support added */
29 /* 3 Counters support added */
30 /* 4 Comments support added */
31 #define IPSET_TYPE_REV_MAX 5 /* Forceadd support added */
33 MODULE_LICENSE("GPL");
34 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
35 IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
36 MODULE_ALIAS("ip_set_hash:net,iface");
38 /* Interface name rbtree */
45 #define iface_data(n) (rb_entry(n, struct iface_node, node)->iface)
48 rbtree_destroy(struct rb_root *root)
50 struct iface_node *node, *next;
52 rbtree_postorder_for_each_entry_safe(node, next, root, node)
59 iface_test(struct rb_root *root, const char **iface)
61 struct rb_node *n = root->rb_node;
64 const char *d = iface_data(n);
65 int res = strcmp(*iface, d);
80 iface_add(struct rb_root *root, const char **iface)
82 struct rb_node **n = &(root->rb_node), *p = NULL;
86 char *ifname = iface_data(*n);
87 int res = strcmp(*iface, ifname);
93 n = &((*n)->rb_right);
100 d = kzalloc(sizeof(*d), GFP_ATOMIC);
103 strcpy(d->iface, *iface);
105 rb_link_node(&d->node, p, n);
106 rb_insert_color(&d->node, root);
112 /* Type specific function prefix */
113 #define HTYPE hash_netiface
114 #define IP_SET_HASH_WITH_NETS
115 #define IP_SET_HASH_WITH_RBTREE
116 #define IP_SET_HASH_WITH_MULTI
118 #define STREQ(a, b) (strcmp(a, b) == 0)
122 struct hash_netiface4_elem_hashed {
130 /* Member elements */
131 struct hash_netiface4_elem {
140 /* Common functions */
143 hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
144 const struct hash_netiface4_elem *ip2,
147 return ip1->ip == ip2->ip &&
148 ip1->cidr == ip2->cidr &&
150 ip1->physdev == ip2->physdev &&
151 ip1->iface == ip2->iface;
155 hash_netiface4_do_data_match(const struct hash_netiface4_elem *elem)
157 return elem->nomatch ? -ENOTEMPTY : 1;
161 hash_netiface4_data_set_flags(struct hash_netiface4_elem *elem, u32 flags)
163 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
167 hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
169 swap(*flags, elem->nomatch);
173 hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
175 elem->ip &= ip_set_netmask(cidr);
180 hash_netiface4_data_list(struct sk_buff *skb,
181 const struct hash_netiface4_elem *data)
183 u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
186 flags |= IPSET_FLAG_NOMATCH;
187 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
188 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
189 nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
191 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
192 goto nla_put_failure;
200 hash_netiface4_data_next(struct hash_netiface4_elem *next,
201 const struct hash_netiface4_elem *d)
206 #define MTYPE hash_netiface4
209 #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
210 #include "ip_set_hash_gen.h"
213 hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
214 const struct xt_action_param *par,
215 enum ipset_adt adt, struct ip_set_adt_opt *opt)
217 struct hash_netiface *h = set->data;
218 ipset_adtfn adtfn = set->variant->adt[adt];
219 struct hash_netiface4_elem e = {
220 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
223 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
228 if (adt == IPSET_TEST)
231 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
232 e.ip &= ip_set_netmask(e.cidr);
234 #define IFACE(dir) (par->dir ? par->dir->name : NULL)
235 #define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
236 #define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC)
238 if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
239 #ifdef CONFIG_BRIDGE_NETFILTER
240 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
244 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
250 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
254 ret = iface_test(&h->rbtree, &e.iface);
255 if (adt == IPSET_ADD) {
257 ret = iface_add(&h->rbtree, &e.iface);
264 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
268 hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
269 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
271 struct hash_netiface *h = set->data;
272 ipset_adtfn adtfn = set->variant->adt[adt];
273 struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
274 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
275 u32 ip = 0, ip_to = 0, last;
276 char iface[IFNAMSIZ];
279 if (unlikely(!tb[IPSET_ATTR_IP] ||
280 !tb[IPSET_ATTR_IFACE] ||
281 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
282 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
283 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
284 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
285 return -IPSET_ERR_PROTOCOL;
287 if (tb[IPSET_ATTR_LINENO])
288 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
290 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
291 ip_set_get_extensions(set, tb, &ext);
295 if (tb[IPSET_ATTR_CIDR]) {
296 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
297 if (e.cidr > HOST_MASK)
298 return -IPSET_ERR_INVALID_CIDR;
301 strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
303 ret = iface_test(&h->rbtree, &e.iface);
304 if (adt == IPSET_ADD) {
306 ret = iface_add(&h->rbtree, &e.iface);
313 if (tb[IPSET_ATTR_CADT_FLAGS]) {
314 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
315 if (cadt_flags & IPSET_FLAG_PHYSDEV)
317 if (cadt_flags & IPSET_FLAG_NOMATCH)
318 flags |= (IPSET_FLAG_NOMATCH << 16);
320 if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
321 e.ip = htonl(ip & ip_set_hostmask(e.cidr));
322 ret = adtfn(set, &e, &ext, &ext, flags);
323 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
324 ip_set_eexist(ret, flags) ? 0 : ret;
327 if (tb[IPSET_ATTR_IP_TO]) {
328 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
333 if (ip + UINT_MAX == ip_to)
334 return -IPSET_ERR_HASH_RANGE;
336 ip_set_mask_from_to(ip, ip_to, e.cidr);
339 ip = ntohl(h->next.ip);
340 while (!after(ip, ip_to)) {
342 last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
343 ret = adtfn(set, &e, &ext, &ext, flags);
345 if (ret && !ip_set_eexist(ret, flags))
356 struct hash_netiface6_elem_hashed {
357 union nf_inet_addr ip;
364 struct hash_netiface6_elem {
365 union nf_inet_addr ip;
373 /* Common functions */
376 hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
377 const struct hash_netiface6_elem *ip2,
380 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
381 ip1->cidr == ip2->cidr &&
383 ip1->physdev == ip2->physdev &&
384 ip1->iface == ip2->iface;
388 hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
390 return elem->nomatch ? -ENOTEMPTY : 1;
394 hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
396 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
400 hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
402 swap(*flags, elem->nomatch);
406 hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
408 ip6_netmask(&elem->ip, cidr);
413 hash_netiface6_data_list(struct sk_buff *skb,
414 const struct hash_netiface6_elem *data)
416 u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
419 flags |= IPSET_FLAG_NOMATCH;
420 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
421 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
422 nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
424 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
425 goto nla_put_failure;
433 hash_netiface6_data_next(struct hash_netiface4_elem *next,
434 const struct hash_netiface6_elem *d)
443 #define MTYPE hash_netiface6
445 #define HOST_MASK 128
446 #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
447 #define IP_SET_EMIT_CREATE
448 #include "ip_set_hash_gen.h"
451 hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
452 const struct xt_action_param *par,
453 enum ipset_adt adt, struct ip_set_adt_opt *opt)
455 struct hash_netiface *h = set->data;
456 ipset_adtfn adtfn = set->variant->adt[adt];
457 struct hash_netiface6_elem e = {
458 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
461 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
466 if (adt == IPSET_TEST)
469 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
470 ip6_netmask(&e.ip, e.cidr);
472 if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
473 #ifdef CONFIG_BRIDGE_NETFILTER
474 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
478 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
484 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
488 ret = iface_test(&h->rbtree, &e.iface);
489 if (adt == IPSET_ADD) {
491 ret = iface_add(&h->rbtree, &e.iface);
498 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
502 hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
503 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
505 struct hash_netiface *h = set->data;
506 ipset_adtfn adtfn = set->variant->adt[adt];
507 struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
508 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
509 char iface[IFNAMSIZ];
512 if (unlikely(!tb[IPSET_ATTR_IP] ||
513 !tb[IPSET_ATTR_IFACE] ||
514 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
515 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
516 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
517 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
518 return -IPSET_ERR_PROTOCOL;
519 if (unlikely(tb[IPSET_ATTR_IP_TO]))
520 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
522 if (tb[IPSET_ATTR_LINENO])
523 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
525 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
526 ip_set_get_extensions(set, tb, &ext);
530 if (tb[IPSET_ATTR_CIDR])
531 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
532 if (e.cidr > HOST_MASK)
533 return -IPSET_ERR_INVALID_CIDR;
534 ip6_netmask(&e.ip, e.cidr);
536 strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
538 ret = iface_test(&h->rbtree, &e.iface);
539 if (adt == IPSET_ADD) {
541 ret = iface_add(&h->rbtree, &e.iface);
548 if (tb[IPSET_ATTR_CADT_FLAGS]) {
549 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
550 if (cadt_flags & IPSET_FLAG_PHYSDEV)
552 if (cadt_flags & IPSET_FLAG_NOMATCH)
553 flags |= (IPSET_FLAG_NOMATCH << 16);
556 ret = adtfn(set, &e, &ext, &ext, flags);
558 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
559 ip_set_eexist(ret, flags) ? 0 : ret;
562 static struct ip_set_type hash_netiface_type __read_mostly = {
563 .name = "hash:net,iface",
564 .protocol = IPSET_PROTOCOL,
565 .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
567 .dimension = IPSET_DIM_TWO,
568 .family = NFPROTO_UNSPEC,
569 .revision_min = IPSET_TYPE_REV_MIN,
570 .revision_max = IPSET_TYPE_REV_MAX,
571 .create = hash_netiface_create,
573 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
574 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
575 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
576 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
577 [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
578 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
579 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
582 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
583 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
584 [IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING,
585 .len = IFNAMSIZ - 1 },
586 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
587 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
588 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
589 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
590 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
591 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
592 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
598 hash_netiface_init(void)
600 return ip_set_type_register(&hash_netiface_type);
604 hash_netiface_fini(void)
606 ip_set_type_unregister(&hash_netiface_type);
609 module_init(hash_netiface_init);
610 module_exit(hash_netiface_fini);