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 MODULE_LICENSE("GPL");
20 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
21 MODULE_DESCRIPTION("list:set type of IP sets");
22 MODULE_ALIAS("ip_set_list:set");
24 /* Member elements without and with timeout */
31 unsigned long timeout;
36 size_t dsize; /* element size */
37 u32 size; /* size of set list array */
38 u32 timeout; /* timeout value */
39 struct timer_list gc; /* garbage collection */
40 struct set_elem members[0]; /* the set members */
43 static inline struct set_elem *
44 list_set_elem(const struct list_set *map, u32 id)
46 return (struct set_elem *)((void *)map->members + id * map->dsize);
49 static inline struct set_telem *
50 list_set_telem(const struct list_set *map, u32 id)
52 return (struct set_telem *)((void *)map->members + id * map->dsize);
56 list_set_timeout(const struct list_set *map, u32 id)
58 const struct set_telem *elem = list_set_telem(map, id);
60 return ip_set_timeout_test(elem->timeout);
64 list_set_expired(const struct list_set *map, u32 id)
66 const struct set_telem *elem = list_set_telem(map, id);
68 return ip_set_timeout_expired(elem->timeout);
71 /* Set list without and with timeout */
74 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
75 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
77 struct list_set *map = set->data;
78 struct set_elem *elem;
82 for (i = 0; i < map->size; i++) {
83 elem = list_set_elem(map, i);
84 if (elem->id == IPSET_INVALID_ID)
86 if (with_timeout(map->timeout) && list_set_expired(map, i))
90 ret = ip_set_test(elem->id, skb, pf, dim, flags);
95 ret = ip_set_add(elem->id, skb, pf, dim, flags);
100 ret = ip_set_del(elem->id, skb, pf, dim, flags);
112 next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
114 const struct set_elem *elem;
116 if (i + 1 < map->size) {
117 elem = list_set_elem(map, i + 1);
118 return !!(elem->id == id &&
119 !(with_timeout(map->timeout) &&
120 list_set_expired(map, i + 1)));
127 list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
131 for (; i < map->size; i++) {
132 e = list_set_elem(map, i);
134 if (e->id == IPSET_INVALID_ID)
140 list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
141 unsigned long timeout)
145 for (; i < map->size; i++) {
146 e = list_set_telem(map, i);
148 swap(e->timeout, timeout);
149 if (e->id == IPSET_INVALID_ID)
155 list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
156 unsigned long timeout)
158 const struct set_elem *e = list_set_elem(map, i);
160 if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
161 /* Last element replaced: e.g. add new,before,last */
162 ip_set_put_byindex(e->id);
163 if (with_timeout(map->timeout))
164 list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
166 list_elem_add(map, i, id);
172 list_set_del(struct list_set *map, u32 i)
174 struct set_elem *a = list_set_elem(map, i), *b;
176 ip_set_put_byindex(a->id);
178 for (; i < map->size - 1; i++) {
179 b = list_set_elem(map, i + 1);
181 if (with_timeout(map->timeout))
182 ((struct set_telem *)a)->timeout =
183 ((struct set_telem *)b)->timeout;
185 if (a->id == IPSET_INVALID_ID)
189 a->id = IPSET_INVALID_ID;
194 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
195 enum ipset_adt adt, u32 *lineno, u32 flags)
197 struct list_set *map = set->data;
198 bool with_timeout = with_timeout(map->timeout);
200 u32 timeout = map->timeout;
201 ip_set_id_t id, refid = IPSET_INVALID_ID;
202 const struct set_elem *elem;
207 if (unlikely(!tb[IPSET_ATTR_NAME] ||
208 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
209 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
210 return -IPSET_ERR_PROTOCOL;
212 if (tb[IPSET_ATTR_LINENO])
213 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
215 id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
216 if (id == IPSET_INVALID_ID)
217 return -IPSET_ERR_NAME;
218 /* "Loop detection" */
219 if (s->type->features & IPSET_TYPE_NAME) {
220 ret = -IPSET_ERR_LOOP;
224 if (tb[IPSET_ATTR_CADT_FLAGS]) {
225 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
226 before = f & IPSET_FLAG_BEFORE;
229 if (before && !tb[IPSET_ATTR_NAMEREF]) {
230 ret = -IPSET_ERR_BEFORE;
234 if (tb[IPSET_ATTR_NAMEREF]) {
235 refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
237 if (refid == IPSET_INVALID_ID) {
238 ret = -IPSET_ERR_NAMEREF;
244 if (tb[IPSET_ATTR_TIMEOUT]) {
246 ret = -IPSET_ERR_TIMEOUT;
249 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
254 for (i = 0; i < map->size && !ret; i++) {
255 elem = list_set_elem(map, i);
256 if (elem->id == IPSET_INVALID_ID ||
257 (before != 0 && i + 1 >= map->size))
259 else if (with_timeout && list_set_expired(map, i))
261 else if (before > 0 && elem->id == id)
262 ret = next_id_eq(map, i, refid);
263 else if (before < 0 && elem->id == refid)
264 ret = next_id_eq(map, i, id);
265 else if (before == 0 && elem->id == id)
270 for (i = 0; i < map->size && !ret; i++) {
271 elem = list_set_elem(map, i);
272 if (elem->id == id &&
273 !(with_timeout && list_set_expired(map, i)))
274 ret = -IPSET_ERR_EXIST;
276 if (ret == -IPSET_ERR_EXIST)
278 ret = -IPSET_ERR_LIST_FULL;
279 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
280 elem = list_set_elem(map, i);
281 if (elem->id == IPSET_INVALID_ID)
282 ret = before != 0 ? -IPSET_ERR_REF_EXIST
283 : list_set_add(map, i, id, timeout);
284 else if (elem->id != refid)
286 else if (with_timeout && list_set_expired(map, i))
287 ret = -IPSET_ERR_REF_EXIST;
289 ret = list_set_add(map, i, id, timeout);
290 else if (i + 1 < map->size)
291 ret = list_set_add(map, i + 1, id, timeout);
295 ret = -IPSET_ERR_EXIST;
296 for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
297 elem = list_set_elem(map, i);
298 if (elem->id == IPSET_INVALID_ID) {
299 ret = before != 0 ? -IPSET_ERR_REF_EXIST
302 } else if (with_timeout && list_set_expired(map, i))
304 else if (elem->id == id &&
307 next_id_eq(map, i, refid))))
308 ret = list_set_del(map, i);
309 else if (before < 0 &&
311 next_id_eq(map, i, id))
312 ret = list_set_del(map, i + 1);
320 if (refid != IPSET_INVALID_ID)
321 ip_set_put_byindex(refid);
322 if (adt != IPSET_ADD || ret)
323 ip_set_put_byindex(id);
325 return ip_set_eexist(ret, flags) ? 0 : ret;
329 list_set_flush(struct ip_set *set)
331 struct list_set *map = set->data;
332 struct set_elem *elem;
335 for (i = 0; i < map->size; i++) {
336 elem = list_set_elem(map, i);
337 if (elem->id != IPSET_INVALID_ID) {
338 ip_set_put_byindex(elem->id);
339 elem->id = IPSET_INVALID_ID;
345 list_set_destroy(struct ip_set *set)
347 struct list_set *map = set->data;
349 if (with_timeout(map->timeout))
350 del_timer_sync(&map->gc);
358 list_set_head(struct ip_set *set, struct sk_buff *skb)
360 const struct list_set *map = set->data;
361 struct nlattr *nested;
363 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
365 goto nla_put_failure;
366 NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
367 if (with_timeout(map->timeout))
368 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
369 NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
370 htonl(atomic_read(&set->ref) - 1));
371 NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
372 htonl(sizeof(*map) + map->size * map->dsize));
373 ipset_nest_end(skb, nested);
381 list_set_list(const struct ip_set *set,
382 struct sk_buff *skb, struct netlink_callback *cb)
384 const struct list_set *map = set->data;
385 struct nlattr *atd, *nested;
386 u32 i, first = cb->args[2];
387 const struct set_elem *e;
389 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
392 for (; cb->args[2] < map->size; cb->args[2]++) {
394 e = list_set_elem(map, i);
395 if (e->id == IPSET_INVALID_ID)
397 if (with_timeout(map->timeout) && list_set_expired(map, i))
399 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
402 nla_nest_cancel(skb, atd);
405 goto nla_put_failure;
407 NLA_PUT_STRING(skb, IPSET_ATTR_NAME,
408 ip_set_name_byindex(e->id));
409 if (with_timeout(map->timeout)) {
410 const struct set_telem *te =
411 (const struct set_telem *) e;
412 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
413 htonl(ip_set_timeout_get(te->timeout)));
415 ipset_nest_end(skb, nested);
418 ipset_nest_end(skb, atd);
419 /* Set listing finished */
424 nla_nest_cancel(skb, nested);
425 ipset_nest_end(skb, atd);
426 if (unlikely(i == first)) {
434 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
436 const struct list_set *x = a->data;
437 const struct list_set *y = b->data;
439 return x->size == y->size &&
440 x->timeout == y->timeout;
443 static const struct ip_set_type_variant list_set = {
444 .kadt = list_set_kadt,
445 .uadt = list_set_uadt,
446 .destroy = list_set_destroy,
447 .flush = list_set_flush,
448 .head = list_set_head,
449 .list = list_set_list,
450 .same_set = list_set_same_set,
454 list_set_gc(unsigned long ul_set)
456 struct ip_set *set = (struct ip_set *) ul_set;
457 struct list_set *map = set->data;
461 /* nfnl_lock should be called */
462 write_lock_bh(&set->lock);
463 for (i = 0; i < map->size; i++) {
464 e = list_set_telem(map, i);
465 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
466 list_set_del(map, i);
468 write_unlock_bh(&set->lock);
470 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
475 list_set_gc_init(struct ip_set *set)
477 struct list_set *map = set->data;
479 init_timer(&map->gc);
480 map->gc.data = (unsigned long) set;
481 map->gc.function = list_set_gc;
482 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
486 /* Create list:set type of sets */
489 init_list_set(struct ip_set *set, u32 size, size_t dsize,
490 unsigned long timeout)
492 struct list_set *map;
496 map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
502 map->timeout = timeout;
505 for (i = 0; i < size; i++) {
506 e = list_set_elem(map, i);
507 e->id = IPSET_INVALID_ID;
514 list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
516 u32 size = IP_SET_LIST_DEFAULT_SIZE;
518 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
519 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
520 return -IPSET_ERR_PROTOCOL;
522 if (tb[IPSET_ATTR_SIZE])
523 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
524 if (size < IP_SET_LIST_MIN_SIZE)
525 size = IP_SET_LIST_MIN_SIZE;
527 if (tb[IPSET_ATTR_TIMEOUT]) {
528 if (!init_list_set(set, size, sizeof(struct set_telem),
529 ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
532 list_set_gc_init(set);
534 if (!init_list_set(set, size, sizeof(struct set_elem),
538 set->variant = &list_set;
542 static struct ip_set_type list_set_type __read_mostly = {
544 .protocol = IPSET_PROTOCOL,
545 .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
546 .dimension = IPSET_DIM_ONE,
549 .create = list_set_create,
551 [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
552 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
555 [IPSET_ATTR_NAME] = { .type = NLA_STRING,
556 .len = IPSET_MAXNAMELEN },
557 [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
558 .len = IPSET_MAXNAMELEN },
559 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
560 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
561 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
569 return ip_set_type_register(&list_set_type);
575 ip_set_type_unregister(&list_set_type);
578 module_init(list_set_init);
579 module_exit(list_set_fini);