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/rculist.h>
13 #include <linux/skbuff.h>
14 #include <linux/errno.h>
16 #include <linux/netfilter/ipset/ip_set.h>
17 #include <linux/netfilter/ipset/ip_set_list.h>
19 #define IPSET_TYPE_REV_MIN 0
20 /* 1 Counters support added */
21 /* 2 Comments support added */
22 #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
26 IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN
, IPSET_TYPE_REV_MAX
);
27 MODULE_ALIAS("ip_set_list:set");
32 struct list_head list
;
34 } __aligned(__alignof__(u64
));
44 u32 size
; /* size of set list array */
45 struct timer_list gc
; /* garbage collection */
46 struct net
*net
; /* namespace */
47 struct list_head members
; /* the set members */
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 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 list_for_each_entry_rcu(e
, &map
->members
, list
) {
65 if (SET_WITH_TIMEOUT(set
) &&
66 ip_set_timeout_expired(ext_timeout(e
, set
)))
68 ret
= ip_set_test(e
->id
, skb
, par
, opt
);
70 if (SET_WITH_COUNTER(set
))
71 ip_set_update_counter(ext_counter(e
, set
),
74 if (SET_WITH_SKBINFO(set
))
75 ip_set_get_skbinfo(ext_skbinfo(e
, set
),
85 list_set_kadd(struct ip_set
*set
, const struct sk_buff
*skb
,
86 const struct xt_action_param
*par
,
87 struct ip_set_adt_opt
*opt
, const struct ip_set_ext
*ext
)
89 struct list_set
*map
= set
->data
;
93 list_for_each_entry(e
, &map
->members
, list
) {
94 if (SET_WITH_TIMEOUT(set
) &&
95 ip_set_timeout_expired(ext_timeout(e
, set
)))
97 ret
= ip_set_add(e
->id
, skb
, par
, opt
);
105 list_set_kdel(struct ip_set
*set
, const struct sk_buff
*skb
,
106 const struct xt_action_param
*par
,
107 struct ip_set_adt_opt
*opt
, const struct ip_set_ext
*ext
)
109 struct list_set
*map
= set
->data
;
113 list_for_each_entry(e
, &map
->members
, list
) {
114 if (SET_WITH_TIMEOUT(set
) &&
115 ip_set_timeout_expired(ext_timeout(e
, set
)))
117 ret
= ip_set_del(e
->id
, skb
, par
, opt
);
125 list_set_kadt(struct ip_set
*set
, const struct sk_buff
*skb
,
126 const struct xt_action_param
*par
,
127 enum ipset_adt adt
, struct ip_set_adt_opt
*opt
)
129 struct ip_set_ext ext
= IP_SET_INIT_KEXT(skb
, opt
, set
);
135 ret
= list_set_ktest(set
, skb
, par
, opt
, &ext
);
138 ret
= list_set_kadd(set
, skb
, par
, opt
, &ext
);
141 ret
= list_set_kdel(set
, skb
, par
, opt
, &ext
);
151 /* Userspace interfaces: we are protected by the nfnl mutex */
154 __list_set_del(struct ip_set
*set
, struct set_elem
*e
)
156 struct list_set
*map
= set
->data
;
158 ip_set_put_byindex(map
->net
, e
->id
);
159 /* We may call it, because we don't have a to be destroyed
160 * extension which is used by the kernel.
162 ip_set_ext_destroy(set
, e
);
167 list_set_del(struct ip_set
*set
, struct set_elem
*e
)
169 list_del_rcu(&e
->list
);
170 __list_set_del(set
, e
);
174 list_set_replace(struct ip_set
*set
, struct set_elem
*e
, struct set_elem
*old
)
176 list_replace_rcu(&old
->list
, &e
->list
);
177 __list_set_del(set
, old
);
181 set_cleanup_entries(struct ip_set
*set
)
183 struct list_set
*map
= set
->data
;
184 struct set_elem
*e
, *n
;
186 list_for_each_entry_safe(e
, n
, &map
->members
, list
)
187 if (ip_set_timeout_expired(ext_timeout(e
, set
)))
188 list_set_del(set
, e
);
192 list_set_utest(struct ip_set
*set
, void *value
, const struct ip_set_ext
*ext
,
193 struct ip_set_ext
*mext
, u32 flags
)
195 struct list_set
*map
= set
->data
;
196 struct set_adt_elem
*d
= value
;
197 struct set_elem
*e
, *next
, *prev
= NULL
;
200 list_for_each_entry(e
, &map
->members
, list
) {
201 if (SET_WITH_TIMEOUT(set
) &&
202 ip_set_timeout_expired(ext_timeout(e
, set
)))
204 else if (e
->id
!= d
->id
) {
209 if (d
->before
== 0) {
211 } else if (d
->before
> 0) {
212 next
= list_next_entry(e
, list
);
213 ret
= !list_is_last(&e
->list
, &map
->members
) &&
214 next
->id
== d
->refid
;
216 ret
= prev
&& prev
->id
== d
->refid
;
224 list_set_init_extensions(struct ip_set
*set
, const struct ip_set_ext
*ext
,
227 if (SET_WITH_COUNTER(set
))
228 ip_set_init_counter(ext_counter(e
, set
), ext
);
229 if (SET_WITH_COMMENT(set
))
230 ip_set_init_comment(ext_comment(e
, set
), ext
);
231 if (SET_WITH_SKBINFO(set
))
232 ip_set_init_skbinfo(ext_skbinfo(e
, set
), ext
);
233 /* Update timeout last */
234 if (SET_WITH_TIMEOUT(set
))
235 ip_set_timeout_set(ext_timeout(e
, set
), ext
->timeout
);
239 list_set_uadd(struct ip_set
*set
, void *value
, const struct ip_set_ext
*ext
,
240 struct ip_set_ext
*mext
, u32 flags
)
242 struct list_set
*map
= set
->data
;
243 struct set_adt_elem
*d
= value
;
244 struct set_elem
*e
, *n
, *prev
, *next
;
245 bool flag_exist
= flags
& IPSET_FLAG_EXIST
;
247 if (SET_WITH_TIMEOUT(set
))
248 set_cleanup_entries(set
);
250 /* Find where to add the new entry */
251 n
= prev
= next
= NULL
;
252 list_for_each_entry(e
, &map
->members
, list
) {
253 if (SET_WITH_TIMEOUT(set
) &&
254 ip_set_timeout_expired(ext_timeout(e
, set
)))
256 else if (d
->id
== e
->id
)
258 else if (d
->before
== 0 || e
->id
!= d
->refid
)
260 else if (d
->before
> 0)
265 /* Re-add already existing element */
267 if ((d
->before
> 0 && !next
) ||
268 (d
->before
< 0 && !prev
))
269 return -IPSET_ERR_REF_EXIST
;
271 return -IPSET_ERR_EXIST
;
272 /* Update extensions */
273 ip_set_ext_destroy(set
, n
);
274 list_set_init_extensions(set
, ext
, n
);
276 /* Set is already added to the list */
277 ip_set_put_byindex(map
->net
, d
->id
);
281 if (d
->before
== 0) {
283 n
= list_empty(&map
->members
) ? NULL
:
284 list_last_entry(&map
->members
, struct set_elem
, list
);
285 } else if (d
->before
> 0) {
286 /* Insert after next element */
287 if (!list_is_last(&next
->list
, &map
->members
))
288 n
= list_next_entry(next
, list
);
290 /* Insert before prev element */
291 if (prev
->list
.prev
!= &map
->members
)
292 n
= list_prev_entry(prev
, list
);
294 /* Can we replace a timed out entry? */
296 !(SET_WITH_TIMEOUT(set
) &&
297 ip_set_timeout_expired(ext_timeout(n
, set
))))
300 e
= kzalloc(set
->dsize
, GFP_ATOMIC
);
304 INIT_LIST_HEAD(&e
->list
);
305 list_set_init_extensions(set
, ext
, e
);
307 list_set_replace(set
, e
, n
);
309 list_add_tail_rcu(&e
->list
, &next
->list
);
311 list_add_rcu(&e
->list
, &prev
->list
);
313 list_add_tail_rcu(&e
->list
, &map
->members
);
319 list_set_udel(struct ip_set
*set
, void *value
, const struct ip_set_ext
*ext
,
320 struct ip_set_ext
*mext
, u32 flags
)
322 struct list_set
*map
= set
->data
;
323 struct set_adt_elem
*d
= value
;
324 struct set_elem
*e
, *next
, *prev
= NULL
;
326 list_for_each_entry(e
, &map
->members
, list
) {
327 if (SET_WITH_TIMEOUT(set
) &&
328 ip_set_timeout_expired(ext_timeout(e
, set
)))
330 else if (e
->id
!= d
->id
) {
336 next
= list_next_entry(e
, list
);
337 if (list_is_last(&e
->list
, &map
->members
) ||
338 next
->id
!= d
->refid
)
339 return -IPSET_ERR_REF_EXIST
;
340 } else if (d
->before
< 0) {
341 if (!prev
|| prev
->id
!= d
->refid
)
342 return -IPSET_ERR_REF_EXIST
;
344 list_set_del(set
, e
);
347 return d
->before
!= 0 ? -IPSET_ERR_REF_EXIST
: -IPSET_ERR_EXIST
;
351 list_set_uadt(struct ip_set
*set
, struct nlattr
*tb
[],
352 enum ipset_adt adt
, u32
*lineno
, u32 flags
, bool retried
)
354 struct list_set
*map
= set
->data
;
355 ipset_adtfn adtfn
= set
->variant
->adt
[adt
];
356 struct set_adt_elem e
= { .refid
= IPSET_INVALID_ID
};
357 struct ip_set_ext ext
= IP_SET_INIT_UEXT(set
);
361 if (tb
[IPSET_ATTR_LINENO
])
362 *lineno
= nla_get_u32(tb
[IPSET_ATTR_LINENO
]);
364 if (unlikely(!tb
[IPSET_ATTR_NAME
] ||
365 !ip_set_optattr_netorder(tb
, IPSET_ATTR_CADT_FLAGS
)))
366 return -IPSET_ERR_PROTOCOL
;
368 ret
= ip_set_get_extensions(set
, tb
, &ext
);
371 e
.id
= ip_set_get_byname(map
->net
, nla_data(tb
[IPSET_ATTR_NAME
]), &s
);
372 if (e
.id
== IPSET_INVALID_ID
)
373 return -IPSET_ERR_NAME
;
374 /* "Loop detection" */
375 if (s
->type
->features
& IPSET_TYPE_NAME
) {
376 ret
= -IPSET_ERR_LOOP
;
380 if (tb
[IPSET_ATTR_CADT_FLAGS
]) {
381 u32 f
= ip_set_get_h32(tb
[IPSET_ATTR_CADT_FLAGS
]);
383 e
.before
= f
& IPSET_FLAG_BEFORE
;
386 if (e
.before
&& !tb
[IPSET_ATTR_NAMEREF
]) {
387 ret
= -IPSET_ERR_BEFORE
;
391 if (tb
[IPSET_ATTR_NAMEREF
]) {
392 e
.refid
= ip_set_get_byname(map
->net
,
393 nla_data(tb
[IPSET_ATTR_NAMEREF
]),
395 if (e
.refid
== IPSET_INVALID_ID
) {
396 ret
= -IPSET_ERR_NAMEREF
;
402 if (adt
!= IPSET_TEST
&& SET_WITH_TIMEOUT(set
))
403 set_cleanup_entries(set
);
405 ret
= adtfn(set
, &e
, &ext
, &ext
, flags
);
408 if (e
.refid
!= IPSET_INVALID_ID
)
409 ip_set_put_byindex(map
->net
, e
.refid
);
410 if (adt
!= IPSET_ADD
|| ret
)
411 ip_set_put_byindex(map
->net
, e
.id
);
413 return ip_set_eexist(ret
, flags
) ? 0 : ret
;
417 list_set_flush(struct ip_set
*set
)
419 struct list_set
*map
= set
->data
;
420 struct set_elem
*e
, *n
;
422 list_for_each_entry_safe(e
, n
, &map
->members
, list
)
423 list_set_del(set
, e
);
427 list_set_destroy(struct ip_set
*set
)
429 struct list_set
*map
= set
->data
;
430 struct set_elem
*e
, *n
;
432 if (SET_WITH_TIMEOUT(set
))
433 del_timer_sync(&map
->gc
);
434 list_for_each_entry_safe(e
, n
, &map
->members
, list
) {
436 ip_set_put_byindex(map
->net
, e
->id
);
437 ip_set_ext_destroy(set
, e
);
446 list_set_head(struct ip_set
*set
, struct sk_buff
*skb
)
448 const struct list_set
*map
= set
->data
;
449 struct nlattr
*nested
;
453 list_for_each_entry(e
, &map
->members
, list
)
456 nested
= ipset_nest_start(skb
, IPSET_ATTR_DATA
);
458 goto nla_put_failure
;
459 if (nla_put_net32(skb
, IPSET_ATTR_SIZE
, htonl(map
->size
)) ||
460 nla_put_net32(skb
, IPSET_ATTR_REFERENCES
, htonl(set
->ref
- 1)) ||
461 nla_put_net32(skb
, IPSET_ATTR_MEMSIZE
,
462 htonl(sizeof(*map
) + n
* set
->dsize
)))
463 goto nla_put_failure
;
464 if (unlikely(ip_set_put_flags(skb
, set
)))
465 goto nla_put_failure
;
466 ipset_nest_end(skb
, nested
);
474 list_set_list(const struct ip_set
*set
,
475 struct sk_buff
*skb
, struct netlink_callback
*cb
)
477 const struct list_set
*map
= set
->data
;
478 struct nlattr
*atd
, *nested
;
479 u32 i
= 0, first
= cb
->args
[IPSET_CB_ARG0
];
483 atd
= ipset_nest_start(skb
, IPSET_ATTR_ADT
);
486 list_for_each_entry(e
, &map
->members
, list
) {
493 list_for_each_entry_from(e
, &map
->members
, list
) {
495 if (SET_WITH_TIMEOUT(set
) &&
496 ip_set_timeout_expired(ext_timeout(e
, set
)))
498 nested
= ipset_nest_start(skb
, IPSET_ATTR_DATA
);
501 nla_nest_cancel(skb
, atd
);
505 goto nla_put_failure
;
507 if (nla_put_string(skb
, IPSET_ATTR_NAME
,
508 ip_set_name_byindex(map
->net
, e
->id
)))
509 goto nla_put_failure
;
510 if (ip_set_put_extensions(skb
, set
, e
, true))
511 goto nla_put_failure
;
512 ipset_nest_end(skb
, nested
);
515 ipset_nest_end(skb
, atd
);
516 /* Set listing finished */
517 cb
->args
[IPSET_CB_ARG0
] = 0;
521 nla_nest_cancel(skb
, nested
);
522 if (unlikely(i
== first
)) {
523 cb
->args
[IPSET_CB_ARG0
] = 0;
526 cb
->args
[IPSET_CB_ARG0
] = i
- 1;
527 ipset_nest_end(skb
, atd
);
534 list_set_same_set(const struct ip_set
*a
, const struct ip_set
*b
)
536 const struct list_set
*x
= a
->data
;
537 const struct list_set
*y
= b
->data
;
539 return x
->size
== y
->size
&&
540 a
->timeout
== b
->timeout
&&
541 a
->extensions
== b
->extensions
;
544 static const struct ip_set_type_variant set_variant
= {
545 .kadt
= list_set_kadt
,
546 .uadt
= list_set_uadt
,
548 [IPSET_ADD
] = list_set_uadd
,
549 [IPSET_DEL
] = list_set_udel
,
550 [IPSET_TEST
] = list_set_utest
,
552 .destroy
= list_set_destroy
,
553 .flush
= list_set_flush
,
554 .head
= list_set_head
,
555 .list
= list_set_list
,
556 .same_set
= list_set_same_set
,
560 list_set_gc(unsigned long ul_set
)
562 struct ip_set
*set
= (struct ip_set
*)ul_set
;
563 struct list_set
*map
= set
->data
;
565 spin_lock_bh(&set
->lock
);
566 set_cleanup_entries(set
);
567 spin_unlock_bh(&set
->lock
);
569 map
->gc
.expires
= jiffies
+ IPSET_GC_PERIOD(set
->timeout
) * HZ
;
574 list_set_gc_init(struct ip_set
*set
, void (*gc
)(unsigned long ul_set
))
576 struct list_set
*map
= set
->data
;
578 init_timer(&map
->gc
);
579 map
->gc
.data
= (unsigned long)set
;
580 map
->gc
.function
= gc
;
581 map
->gc
.expires
= jiffies
+ IPSET_GC_PERIOD(set
->timeout
) * HZ
;
585 /* Create list:set type of sets */
588 init_list_set(struct net
*net
, struct ip_set
*set
, u32 size
)
590 struct list_set
*map
;
592 map
= kzalloc(sizeof(*map
), GFP_KERNEL
);
598 INIT_LIST_HEAD(&map
->members
);
605 list_set_create(struct net
*net
, struct ip_set
*set
, struct nlattr
*tb
[],
608 u32 size
= IP_SET_LIST_DEFAULT_SIZE
;
610 if (unlikely(!ip_set_optattr_netorder(tb
, IPSET_ATTR_SIZE
) ||
611 !ip_set_optattr_netorder(tb
, IPSET_ATTR_TIMEOUT
) ||
612 !ip_set_optattr_netorder(tb
, IPSET_ATTR_CADT_FLAGS
)))
613 return -IPSET_ERR_PROTOCOL
;
615 if (tb
[IPSET_ATTR_SIZE
])
616 size
= ip_set_get_h32(tb
[IPSET_ATTR_SIZE
]);
617 if (size
< IP_SET_LIST_MIN_SIZE
)
618 size
= IP_SET_LIST_MIN_SIZE
;
620 set
->variant
= &set_variant
;
621 set
->dsize
= ip_set_elem_len(set
, tb
, sizeof(struct set_elem
),
622 __alignof__(struct set_elem
));
623 if (!init_list_set(net
, set
, size
))
625 if (tb
[IPSET_ATTR_TIMEOUT
]) {
626 set
->timeout
= ip_set_timeout_uget(tb
[IPSET_ATTR_TIMEOUT
]);
627 list_set_gc_init(set
, list_set_gc
);
632 static struct ip_set_type list_set_type __read_mostly
= {
634 .protocol
= IPSET_PROTOCOL
,
635 .features
= IPSET_TYPE_NAME
| IPSET_DUMP_LAST
,
636 .dimension
= IPSET_DIM_ONE
,
637 .family
= NFPROTO_UNSPEC
,
638 .revision_min
= IPSET_TYPE_REV_MIN
,
639 .revision_max
= IPSET_TYPE_REV_MAX
,
640 .create
= list_set_create
,
642 [IPSET_ATTR_SIZE
] = { .type
= NLA_U32
},
643 [IPSET_ATTR_TIMEOUT
] = { .type
= NLA_U32
},
644 [IPSET_ATTR_CADT_FLAGS
] = { .type
= NLA_U32
},
647 [IPSET_ATTR_NAME
] = { .type
= NLA_STRING
,
648 .len
= IPSET_MAXNAMELEN
},
649 [IPSET_ATTR_NAMEREF
] = { .type
= NLA_STRING
,
650 .len
= IPSET_MAXNAMELEN
},
651 [IPSET_ATTR_TIMEOUT
] = { .type
= NLA_U32
},
652 [IPSET_ATTR_LINENO
] = { .type
= NLA_U32
},
653 [IPSET_ATTR_CADT_FLAGS
] = { .type
= NLA_U32
},
654 [IPSET_ATTR_BYTES
] = { .type
= NLA_U64
},
655 [IPSET_ATTR_PACKETS
] = { .type
= NLA_U64
},
656 [IPSET_ATTR_COMMENT
] = { .type
= NLA_NUL_STRING
,
657 .len
= IPSET_MAX_COMMENT_SIZE
},
658 [IPSET_ATTR_SKBMARK
] = { .type
= NLA_U64
},
659 [IPSET_ATTR_SKBPRIO
] = { .type
= NLA_U32
},
660 [IPSET_ATTR_SKBQUEUE
] = { .type
= NLA_U16
},
668 return ip_set_type_register(&list_set_type
);
675 ip_set_type_unregister(&list_set_type
);
678 module_init(list_set_init
);
679 module_exit(list_set_fini
);