1 /* Copyright (C) 2008-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 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_timeout.h>
17 #include <linux/netfilter/ipset/ip_set_list.h>
19 #define REVISION_MIN 0
20 #define REVISION_MAX 0
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
24 IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
25 MODULE_ALIAS("ip_set_list:set");
27 /* Member elements without and with timeout */
34 unsigned long timeout;
39 size_t dsize; /* element size */
40 u32 size; /* size of set list array */
41 u32 timeout; /* timeout value */
42 struct timer_list gc; /* garbage collection */
43 struct set_elem members[0]; /* the set members */
46 static inline struct set_elem *
47 list_set_elem(const struct list_set *map, u32 id)
49 return (struct set_elem *)((void *)map->members + id * map->dsize);
52 static inline struct set_telem *
53 list_set_telem(const struct list_set *map, u32 id)
55 return (struct set_telem *)((void *)map->members + id * map->dsize);
59 list_set_timeout(const struct list_set *map, u32 id)
61 const struct set_telem *elem = list_set_telem(map, id);
63 return ip_set_timeout_test(elem->timeout);
67 list_set_expired(const struct list_set *map, u32 id)
69 const struct set_telem *elem = list_set_telem(map, id);
71 return ip_set_timeout_expired(elem->timeout);
74 /* Set list without and with timeout */
77 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
78 const struct xt_action_param *par,
79 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
81 struct list_set *map = set->data;
82 struct set_elem *elem;
86 for (i = 0; i < map->size; i++) {
87 elem = list_set_elem(map, i);
88 if (elem->id == IPSET_INVALID_ID)
90 if (with_timeout(map->timeout) && list_set_expired(map, i))
94 ret = ip_set_test(elem->id, skb, par, opt);
99 ret = ip_set_add(elem->id, skb, par, opt);
104 ret = ip_set_del(elem->id, skb, par, opt);
116 id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
118 const struct set_elem *elem;
121 elem = list_set_elem(map, i);
122 return elem->id == id;
129 id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
131 const struct set_elem *elem;
134 elem = list_set_elem(map, i);
135 return !!(elem->id == id &&
136 !(with_timeout(map->timeout) &&
137 list_set_expired(map, i)));
144 list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
148 for (; i < map->size; i++) {
149 e = list_set_elem(map, i);
151 if (e->id == IPSET_INVALID_ID)
157 list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
158 unsigned long timeout)
162 for (; i < map->size; i++) {
163 e = list_set_telem(map, i);
165 swap(e->timeout, timeout);
166 if (e->id == IPSET_INVALID_ID)
172 list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
173 unsigned long timeout)
175 const struct set_elem *e = list_set_elem(map, i);
177 if (e->id != IPSET_INVALID_ID) {
178 const struct set_elem *x = list_set_elem(map, map->size - 1);
180 /* Last element replaced or pushed off */
181 if (x->id != IPSET_INVALID_ID)
182 ip_set_put_byindex(x->id);
184 if (with_timeout(map->timeout))
185 list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
187 list_elem_add(map, i, id);
193 list_set_del(struct list_set *map, u32 i)
195 struct set_elem *a = list_set_elem(map, i), *b;
197 ip_set_put_byindex(a->id);
199 for (; i < map->size - 1; i++) {
200 b = list_set_elem(map, i + 1);
202 if (with_timeout(map->timeout))
203 ((struct set_telem *)a)->timeout =
204 ((struct set_telem *)b)->timeout;
206 if (a->id == IPSET_INVALID_ID)
210 a->id = IPSET_INVALID_ID;
215 cleanup_entries(struct list_set *map)
220 for (i = 0; i < map->size; i++) {
221 e = list_set_telem(map, i);
222 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
223 list_set_del(map, i);
228 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
229 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
231 struct list_set *map = set->data;
232 bool with_timeout = with_timeout(map->timeout);
233 bool flag_exist = flags & IPSET_FLAG_EXIST;
235 u32 timeout = map->timeout;
236 ip_set_id_t id, refid = IPSET_INVALID_ID;
237 const struct set_elem *elem;
242 if (unlikely(!tb[IPSET_ATTR_NAME] ||
243 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
244 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
245 return -IPSET_ERR_PROTOCOL;
247 if (tb[IPSET_ATTR_LINENO])
248 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
250 id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
251 if (id == IPSET_INVALID_ID)
252 return -IPSET_ERR_NAME;
253 /* "Loop detection" */
254 if (s->type->features & IPSET_TYPE_NAME) {
255 ret = -IPSET_ERR_LOOP;
259 if (tb[IPSET_ATTR_CADT_FLAGS]) {
260 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
261 before = f & IPSET_FLAG_BEFORE;
264 if (before && !tb[IPSET_ATTR_NAMEREF]) {
265 ret = -IPSET_ERR_BEFORE;
269 if (tb[IPSET_ATTR_NAMEREF]) {
270 refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
272 if (refid == IPSET_INVALID_ID) {
273 ret = -IPSET_ERR_NAMEREF;
279 if (tb[IPSET_ATTR_TIMEOUT]) {
281 ret = -IPSET_ERR_TIMEOUT;
284 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
286 if (with_timeout && adt != IPSET_TEST)
287 cleanup_entries(map);
291 for (i = 0; i < map->size && !ret; i++) {
292 elem = list_set_elem(map, i);
293 if (elem->id == IPSET_INVALID_ID ||
294 (before != 0 && i + 1 >= map->size))
296 else if (with_timeout && list_set_expired(map, i))
298 else if (before > 0 && elem->id == id)
299 ret = id_eq_timeout(map, i + 1, refid);
300 else if (before < 0 && elem->id == refid)
301 ret = id_eq_timeout(map, i + 1, id);
302 else if (before == 0 && elem->id == id)
307 for (i = 0; i < map->size; i++) {
308 elem = list_set_elem(map, i);
311 if (!(with_timeout && flag_exist)) {
312 ret = -IPSET_ERR_EXIST;
315 struct set_telem *e = list_set_telem(map, i);
318 !id_eq(map, i + 1, refid)) ||
320 (i == 0 || !id_eq(map, i - 1, refid)))) {
321 ret = -IPSET_ERR_EXIST;
324 e->timeout = ip_set_timeout_set(timeout);
325 ip_set_put_byindex(id);
330 ret = -IPSET_ERR_LIST_FULL;
331 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
332 elem = list_set_elem(map, i);
333 if (elem->id == IPSET_INVALID_ID)
334 ret = before != 0 ? -IPSET_ERR_REF_EXIST
335 : list_set_add(map, i, id, timeout);
336 else if (elem->id != refid)
339 ret = list_set_add(map, i, id, timeout);
340 else if (i + 1 < map->size)
341 ret = list_set_add(map, i + 1, id, timeout);
345 ret = -IPSET_ERR_EXIST;
346 for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
347 elem = list_set_elem(map, i);
348 if (elem->id == IPSET_INVALID_ID) {
349 ret = before != 0 ? -IPSET_ERR_REF_EXIST
352 } else if (elem->id == id &&
354 (before > 0 && id_eq(map, i + 1, refid))))
355 ret = list_set_del(map, i);
356 else if (elem->id == refid &&
357 before < 0 && id_eq(map, i + 1, id))
358 ret = list_set_del(map, i + 1);
366 if (refid != IPSET_INVALID_ID)
367 ip_set_put_byindex(refid);
368 if (adt != IPSET_ADD || ret)
369 ip_set_put_byindex(id);
371 return ip_set_eexist(ret, flags) ? 0 : ret;
375 list_set_flush(struct ip_set *set)
377 struct list_set *map = set->data;
378 struct set_elem *elem;
381 for (i = 0; i < map->size; i++) {
382 elem = list_set_elem(map, i);
383 if (elem->id != IPSET_INVALID_ID) {
384 ip_set_put_byindex(elem->id);
385 elem->id = IPSET_INVALID_ID;
391 list_set_destroy(struct ip_set *set)
393 struct list_set *map = set->data;
395 if (with_timeout(map->timeout))
396 del_timer_sync(&map->gc);
404 list_set_head(struct ip_set *set, struct sk_buff *skb)
406 const struct list_set *map = set->data;
407 struct nlattr *nested;
409 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
411 goto nla_put_failure;
412 if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
413 (with_timeout(map->timeout) &&
414 nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
415 nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
416 nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
417 htonl(sizeof(*map) + map->size * map->dsize)))
418 goto nla_put_failure;
419 ipset_nest_end(skb, nested);
427 list_set_list(const struct ip_set *set,
428 struct sk_buff *skb, struct netlink_callback *cb)
430 const struct list_set *map = set->data;
431 struct nlattr *atd, *nested;
432 u32 i, first = cb->args[2];
433 const struct set_elem *e;
435 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
438 for (; cb->args[2] < map->size; cb->args[2]++) {
440 e = list_set_elem(map, i);
441 if (e->id == IPSET_INVALID_ID)
443 if (with_timeout(map->timeout) && list_set_expired(map, i))
445 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
448 nla_nest_cancel(skb, atd);
451 goto nla_put_failure;
453 if (nla_put_string(skb, IPSET_ATTR_NAME,
454 ip_set_name_byindex(e->id)))
455 goto nla_put_failure;
456 if (with_timeout(map->timeout)) {
457 const struct set_telem *te =
458 (const struct set_telem *) e;
459 __be32 to = htonl(ip_set_timeout_get(te->timeout));
460 if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, to))
461 goto nla_put_failure;
463 ipset_nest_end(skb, nested);
466 ipset_nest_end(skb, atd);
467 /* Set listing finished */
472 nla_nest_cancel(skb, nested);
473 ipset_nest_end(skb, atd);
474 if (unlikely(i == first)) {
482 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
484 const struct list_set *x = a->data;
485 const struct list_set *y = b->data;
487 return x->size == y->size &&
488 x->timeout == y->timeout;
491 static const struct ip_set_type_variant list_set = {
492 .kadt = list_set_kadt,
493 .uadt = list_set_uadt,
494 .destroy = list_set_destroy,
495 .flush = list_set_flush,
496 .head = list_set_head,
497 .list = list_set_list,
498 .same_set = list_set_same_set,
502 list_set_gc(unsigned long ul_set)
504 struct ip_set *set = (struct ip_set *) ul_set;
505 struct list_set *map = set->data;
507 write_lock_bh(&set->lock);
508 cleanup_entries(map);
509 write_unlock_bh(&set->lock);
511 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
516 list_set_gc_init(struct ip_set *set)
518 struct list_set *map = set->data;
520 init_timer(&map->gc);
521 map->gc.data = (unsigned long) set;
522 map->gc.function = list_set_gc;
523 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
527 /* Create list:set type of sets */
530 init_list_set(struct ip_set *set, u32 size, size_t dsize,
531 unsigned long timeout)
533 struct list_set *map;
537 map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
543 map->timeout = timeout;
546 for (i = 0; i < size; i++) {
547 e = list_set_elem(map, i);
548 e->id = IPSET_INVALID_ID;
555 list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
557 u32 size = IP_SET_LIST_DEFAULT_SIZE;
559 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
560 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
561 return -IPSET_ERR_PROTOCOL;
563 if (tb[IPSET_ATTR_SIZE])
564 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
565 if (size < IP_SET_LIST_MIN_SIZE)
566 size = IP_SET_LIST_MIN_SIZE;
568 if (tb[IPSET_ATTR_TIMEOUT]) {
569 if (!init_list_set(set, size, sizeof(struct set_telem),
570 ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
573 list_set_gc_init(set);
575 if (!init_list_set(set, size, sizeof(struct set_elem),
579 set->variant = &list_set;
583 static struct ip_set_type list_set_type __read_mostly = {
585 .protocol = IPSET_PROTOCOL,
586 .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
587 .dimension = IPSET_DIM_ONE,
588 .family = NFPROTO_UNSPEC,
589 .revision_min = REVISION_MIN,
590 .revision_max = REVISION_MAX,
591 .create = list_set_create,
593 [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
594 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
597 [IPSET_ATTR_NAME] = { .type = NLA_STRING,
598 .len = IPSET_MAXNAMELEN },
599 [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
600 .len = IPSET_MAXNAMELEN },
601 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
602 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
603 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
611 return ip_set_type_register(&list_set_type);
617 ip_set_type_unregister(&list_set_type);
620 module_init(list_set_init);
621 module_exit(list_set_fini);