1 /* Copyright (C) 2008-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 list:set type */
10 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/errno.h>
15 #include <linux/netfilter/ipset/ip_set.h>
16 #include <linux/netfilter/ipset/ip_set_list.h>
18 #define IPSET_TYPE_REV_MIN 0
19 /* 1 Counters support added */
20 /* 2 Comments support added */
21 #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25 IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
26 MODULE_ALIAS("ip_set_list:set");
41 u32 size; /* size of set list array */
42 struct timer_list gc; /* garbage collection */
43 struct net *net; /* namespace */
44 struct set_elem members[0]; /* the set members */
47 #define list_set_elem(set, map, id) \
48 (struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
51 list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
52 const struct xt_action_param *par,
53 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
55 struct list_set *map = set->data;
57 u32 i, cmdflags = opt->cmdflags;
60 /* Don't lookup sub-counters at all */
61 opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
62 if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
63 opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
64 for (i = 0; i < map->size; i++) {
65 e = list_set_elem(set, map, i);
66 if (e->id == IPSET_INVALID_ID)
68 if (SET_WITH_TIMEOUT(set) &&
69 ip_set_timeout_expired(ext_timeout(e, set)))
71 ret = ip_set_test(e->id, skb, par, opt);
73 if (SET_WITH_COUNTER(set))
74 ip_set_update_counter(ext_counter(e, set),
77 if (SET_WITH_SKBINFO(set))
78 ip_set_get_skbinfo(ext_skbinfo(e, set),
88 list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
89 const struct xt_action_param *par,
90 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
92 struct list_set *map = set->data;
97 for (i = 0; i < map->size; i++) {
98 e = list_set_elem(set, map, i);
99 if (e->id == IPSET_INVALID_ID)
101 if (SET_WITH_TIMEOUT(set) &&
102 ip_set_timeout_expired(ext_timeout(e, set)))
104 ret = ip_set_add(e->id, skb, par, opt);
112 list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
113 const struct xt_action_param *par,
114 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
116 struct list_set *map = set->data;
121 for (i = 0; i < map->size; i++) {
122 e = list_set_elem(set, map, i);
123 if (e->id == IPSET_INVALID_ID)
125 if (SET_WITH_TIMEOUT(set) &&
126 ip_set_timeout_expired(ext_timeout(e, set)))
128 ret = ip_set_del(e->id, skb, par, opt);
136 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
137 const struct xt_action_param *par,
138 enum ipset_adt adt, struct ip_set_adt_opt *opt)
140 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
144 return list_set_ktest(set, skb, par, opt, &ext);
146 return list_set_kadd(set, skb, par, opt, &ext);
148 return list_set_kdel(set, skb, par, opt, &ext);
156 id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
158 const struct list_set *map = set->data;
159 const struct set_elem *e;
164 e = list_set_elem(set, map, i);
165 return !!(e->id == id &&
166 !(SET_WITH_TIMEOUT(set) &&
167 ip_set_timeout_expired(ext_timeout(e, set))));
171 list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
172 const struct ip_set_ext *ext)
174 struct list_set *map = set->data;
175 struct set_elem *e = list_set_elem(set, map, i);
177 if (e->id != IPSET_INVALID_ID) {
178 if (i == map->size - 1) {
179 /* Last element replaced: e.g. add new,before,last */
180 ip_set_put_byindex(map->net, e->id);
181 ip_set_ext_destroy(set, e);
183 struct set_elem *x = list_set_elem(set, map,
186 /* Last element pushed off */
187 if (x->id != IPSET_INVALID_ID) {
188 ip_set_put_byindex(map->net, x->id);
189 ip_set_ext_destroy(set, x);
191 memmove(list_set_elem(set, map, i + 1), e,
192 set->dsize * (map->size - (i + 1)));
193 /* Extensions must be initialized to zero */
194 memset(e, 0, set->dsize);
199 if (SET_WITH_TIMEOUT(set))
200 ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
201 if (SET_WITH_COUNTER(set))
202 ip_set_init_counter(ext_counter(e, set), ext);
203 if (SET_WITH_COMMENT(set))
204 ip_set_init_comment(ext_comment(e, set), ext);
205 if (SET_WITH_SKBINFO(set))
206 ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
211 list_set_del(struct ip_set *set, u32 i)
213 struct list_set *map = set->data;
214 struct set_elem *e = list_set_elem(set, map, i);
216 ip_set_put_byindex(map->net, e->id);
217 ip_set_ext_destroy(set, e);
219 if (i < map->size - 1)
220 memmove(e, list_set_elem(set, map, i + 1),
221 set->dsize * (map->size - (i + 1)));
224 e = list_set_elem(set, map, map->size - 1);
225 e->id = IPSET_INVALID_ID;
230 set_cleanup_entries(struct ip_set *set)
232 struct list_set *map = set->data;
236 while (i < map->size) {
237 e = list_set_elem(set, map, i);
238 if (e->id != IPSET_INVALID_ID &&
239 ip_set_timeout_expired(ext_timeout(e, set)))
240 list_set_del(set, i);
241 /* Check element moved to position i in next loop */
248 list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
249 struct ip_set_ext *mext, u32 flags)
251 struct list_set *map = set->data;
252 struct set_adt_elem *d = value;
257 for (i = 0; i < map->size; i++) {
258 e = list_set_elem(set, map, i);
259 if (e->id == IPSET_INVALID_ID)
261 else if (SET_WITH_TIMEOUT(set) &&
262 ip_set_timeout_expired(ext_timeout(e, set)))
264 else if (e->id != d->id)
269 else if (d->before > 0)
270 ret = id_eq(set, i + 1, d->refid);
272 ret = i > 0 && id_eq(set, i - 1, d->refid);
280 list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
281 struct ip_set_ext *mext, u32 flags)
283 struct list_set *map = set->data;
284 struct set_adt_elem *d = value;
286 bool flag_exist = flags & IPSET_FLAG_EXIST;
289 if (SET_WITH_TIMEOUT(set))
290 set_cleanup_entries(set);
292 /* Check already added element */
293 for (i = 0; i < map->size; i++) {
294 e = list_set_elem(set, map, i);
295 if (e->id == IPSET_INVALID_ID)
297 else if (e->id != d->id)
300 if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
302 (i == 0 || !id_eq(set, i - 1, d->refid))))
303 /* Before/after doesn't match */
304 return -IPSET_ERR_REF_EXIST;
307 return -IPSET_ERR_EXIST;
308 /* Update extensions */
309 ip_set_ext_destroy(set, e);
311 if (SET_WITH_TIMEOUT(set))
312 ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
313 if (SET_WITH_COUNTER(set))
314 ip_set_init_counter(ext_counter(e, set), ext);
315 if (SET_WITH_COMMENT(set))
316 ip_set_init_comment(ext_comment(e, set), ext);
317 if (SET_WITH_SKBINFO(set))
318 ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
319 /* Set is already added to the list */
320 ip_set_put_byindex(map->net, d->id);
324 ret = -IPSET_ERR_LIST_FULL;
325 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
326 e = list_set_elem(set, map, i);
327 if (e->id == IPSET_INVALID_ID)
328 ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
329 : list_set_add(set, i, d, ext);
330 else if (e->id != d->refid)
332 else if (d->before > 0)
333 ret = list_set_add(set, i, d, ext);
334 else if (i + 1 < map->size)
335 ret = list_set_add(set, i + 1, d, ext);
342 list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
343 struct ip_set_ext *mext, u32 flags)
345 struct list_set *map = set->data;
346 struct set_adt_elem *d = value;
350 for (i = 0; i < map->size; i++) {
351 e = list_set_elem(set, map, i);
352 if (e->id == IPSET_INVALID_ID)
353 return d->before != 0 ? -IPSET_ERR_REF_EXIST
355 else if (SET_WITH_TIMEOUT(set) &&
356 ip_set_timeout_expired(ext_timeout(e, set)))
358 else if (e->id != d->id)
362 return list_set_del(set, i);
363 else if (d->before > 0) {
364 if (!id_eq(set, i + 1, d->refid))
365 return -IPSET_ERR_REF_EXIST;
366 return list_set_del(set, i);
367 } else if (i == 0 || !id_eq(set, i - 1, d->refid))
368 return -IPSET_ERR_REF_EXIST;
370 return list_set_del(set, i);
372 return -IPSET_ERR_EXIST;
376 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
377 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
379 struct list_set *map = set->data;
380 ipset_adtfn adtfn = set->variant->adt[adt];
381 struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
382 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
386 if (unlikely(!tb[IPSET_ATTR_NAME] ||
387 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
388 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
389 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
390 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
391 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
392 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
393 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
394 return -IPSET_ERR_PROTOCOL;
396 if (tb[IPSET_ATTR_LINENO])
397 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
399 ret = ip_set_get_extensions(set, tb, &ext);
402 e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
403 if (e.id == IPSET_INVALID_ID)
404 return -IPSET_ERR_NAME;
405 /* "Loop detection" */
406 if (s->type->features & IPSET_TYPE_NAME) {
407 ret = -IPSET_ERR_LOOP;
411 if (tb[IPSET_ATTR_CADT_FLAGS]) {
412 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
413 e.before = f & IPSET_FLAG_BEFORE;
416 if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
417 ret = -IPSET_ERR_BEFORE;
421 if (tb[IPSET_ATTR_NAMEREF]) {
422 e.refid = ip_set_get_byname(map->net,
423 nla_data(tb[IPSET_ATTR_NAMEREF]),
425 if (e.refid == IPSET_INVALID_ID) {
426 ret = -IPSET_ERR_NAMEREF;
432 if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
433 set_cleanup_entries(set);
435 ret = adtfn(set, &e, &ext, &ext, flags);
438 if (e.refid != IPSET_INVALID_ID)
439 ip_set_put_byindex(map->net, e.refid);
440 if (adt != IPSET_ADD || ret)
441 ip_set_put_byindex(map->net, e.id);
443 return ip_set_eexist(ret, flags) ? 0 : ret;
447 list_set_flush(struct ip_set *set)
449 struct list_set *map = set->data;
453 for (i = 0; i < map->size; i++) {
454 e = list_set_elem(set, map, i);
455 if (e->id != IPSET_INVALID_ID) {
456 ip_set_put_byindex(map->net, e->id);
457 ip_set_ext_destroy(set, e);
458 e->id = IPSET_INVALID_ID;
464 list_set_destroy(struct ip_set *set)
466 struct list_set *map = set->data;
468 if (SET_WITH_TIMEOUT(set))
469 del_timer_sync(&map->gc);
477 list_set_head(struct ip_set *set, struct sk_buff *skb)
479 const struct list_set *map = set->data;
480 struct nlattr *nested;
482 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
484 goto nla_put_failure;
485 if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
486 nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
487 nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
488 htonl(sizeof(*map) + map->size * set->dsize)))
489 goto nla_put_failure;
490 if (unlikely(ip_set_put_flags(skb, set)))
491 goto nla_put_failure;
492 ipset_nest_end(skb, nested);
500 list_set_list(const struct ip_set *set,
501 struct sk_buff *skb, struct netlink_callback *cb)
503 const struct list_set *map = set->data;
504 struct nlattr *atd, *nested;
505 u32 i, first = cb->args[IPSET_CB_ARG0];
506 const struct set_elem *e;
508 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
511 for (; cb->args[IPSET_CB_ARG0] < map->size;
512 cb->args[IPSET_CB_ARG0]++) {
513 i = cb->args[IPSET_CB_ARG0];
514 e = list_set_elem(set, map, i);
515 if (e->id == IPSET_INVALID_ID)
517 if (SET_WITH_TIMEOUT(set) &&
518 ip_set_timeout_expired(ext_timeout(e, set)))
520 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
523 nla_nest_cancel(skb, atd);
526 goto nla_put_failure;
528 if (nla_put_string(skb, IPSET_ATTR_NAME,
529 ip_set_name_byindex(map->net, e->id)))
530 goto nla_put_failure;
531 if (ip_set_put_extensions(skb, set, e, true))
532 goto nla_put_failure;
533 ipset_nest_end(skb, nested);
536 ipset_nest_end(skb, atd);
537 /* Set listing finished */
538 cb->args[IPSET_CB_ARG0] = 0;
542 nla_nest_cancel(skb, nested);
543 if (unlikely(i == first)) {
544 cb->args[IPSET_CB_ARG0] = 0;
547 ipset_nest_end(skb, atd);
552 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
554 const struct list_set *x = a->data;
555 const struct list_set *y = b->data;
557 return x->size == y->size &&
558 a->timeout == b->timeout &&
559 a->extensions == b->extensions;
562 static const struct ip_set_type_variant set_variant = {
563 .kadt = list_set_kadt,
564 .uadt = list_set_uadt,
566 [IPSET_ADD] = list_set_uadd,
567 [IPSET_DEL] = list_set_udel,
568 [IPSET_TEST] = list_set_utest,
570 .destroy = list_set_destroy,
571 .flush = list_set_flush,
572 .head = list_set_head,
573 .list = list_set_list,
574 .same_set = list_set_same_set,
578 list_set_gc(unsigned long ul_set)
580 struct ip_set *set = (struct ip_set *) ul_set;
581 struct list_set *map = set->data;
583 write_lock_bh(&set->lock);
584 set_cleanup_entries(set);
585 write_unlock_bh(&set->lock);
587 map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
592 list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
594 struct list_set *map = set->data;
596 init_timer(&map->gc);
597 map->gc.data = (unsigned long) set;
598 map->gc.function = gc;
599 map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
603 /* Create list:set type of sets */
606 init_list_set(struct net *net, struct ip_set *set, u32 size)
608 struct list_set *map;
612 map = kzalloc(sizeof(*map) +
613 min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize,
622 for (i = 0; i < size; i++) {
623 e = list_set_elem(set, map, i);
624 e->id = IPSET_INVALID_ID;
631 list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
634 u32 size = IP_SET_LIST_DEFAULT_SIZE;
636 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
637 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
638 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
639 return -IPSET_ERR_PROTOCOL;
641 if (tb[IPSET_ATTR_SIZE])
642 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
643 if (size < IP_SET_LIST_MIN_SIZE)
644 size = IP_SET_LIST_MIN_SIZE;
646 set->variant = &set_variant;
647 set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
648 if (!init_list_set(net, set, size))
650 if (tb[IPSET_ATTR_TIMEOUT]) {
651 set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
652 list_set_gc_init(set, list_set_gc);
657 static struct ip_set_type list_set_type __read_mostly = {
659 .protocol = IPSET_PROTOCOL,
660 .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
661 .dimension = IPSET_DIM_ONE,
662 .family = NFPROTO_UNSPEC,
663 .revision_min = IPSET_TYPE_REV_MIN,
664 .revision_max = IPSET_TYPE_REV_MAX,
665 .create = list_set_create,
667 [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
668 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
669 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
672 [IPSET_ATTR_NAME] = { .type = NLA_STRING,
673 .len = IPSET_MAXNAMELEN },
674 [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
675 .len = IPSET_MAXNAMELEN },
676 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
677 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
678 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
679 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
680 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
681 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
682 .len = IPSET_MAX_COMMENT_SIZE },
683 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
684 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
685 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
693 return ip_set_type_register(&list_set_type);
699 ip_set_type_unregister(&list_set_type);
702 module_init(list_set_init);
703 module_exit(list_set_fini);