1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Martin Josefsson <gandalf@wlug.westbo.se>
4 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 /* Kernel module which implements the set match and SET target
12 * for netfilter/iptables. */
14 #include <linux/module.h>
15 #include <linux/skbuff.h>
17 #include <linux/netfilter/x_tables.h>
18 #include <linux/netfilter/xt_set.h>
19 #include <linux/netfilter/ipset/ip_set_timeout.h>
21 MODULE_LICENSE("GPL");
22 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
23 MODULE_DESCRIPTION("Xtables: IP set match and target module");
24 MODULE_ALIAS("xt_SET");
25 MODULE_ALIAS("ipt_set");
26 MODULE_ALIAS("ip6t_set");
27 MODULE_ALIAS("ipt_SET");
28 MODULE_ALIAS("ip6t_SET");
31 match_set(ip_set_id_t index
, const struct sk_buff
*skb
,
32 const struct xt_action_param
*par
,
33 struct ip_set_adt_opt
*opt
, int inv
)
35 if (ip_set_test(index
, skb
, par
, opt
))
40 #define ADT_OPT(n, f, d, fs, cfs, t) \
41 struct ip_set_adt_opt n = { \
49 /* Revision 0 interface: backward compatible with netfilter/iptables */
52 set_match_v0(const struct sk_buff
*skb
, struct xt_action_param
*par
)
54 const struct xt_set_info_match_v0
*info
= par
->matchinfo
;
55 ADT_OPT(opt
, par
->family
, info
->match_set
.u
.compat
.dim
,
56 info
->match_set
.u
.compat
.flags
, 0, UINT_MAX
);
58 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
59 info
->match_set
.u
.compat
.flags
& IPSET_INV_MATCH
);
63 compat_flags(struct xt_set_info_v0
*info
)
67 /* Fill out compatibility data according to enum ip_set_kopt */
68 info
->u
.compat
.dim
= IPSET_DIM_ZERO
;
69 if (info
->u
.flags
[0] & IPSET_MATCH_INV
)
70 info
->u
.compat
.flags
|= IPSET_INV_MATCH
;
71 for (i
= 0; i
< IPSET_DIM_MAX
-1 && info
->u
.flags
[i
]; i
++) {
73 if (info
->u
.flags
[i
] & IPSET_SRC
)
74 info
->u
.compat
.flags
|= (1<<info
->u
.compat
.dim
);
79 set_match_v0_checkentry(const struct xt_mtchk_param
*par
)
81 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
84 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
86 if (index
== IPSET_INVALID_ID
) {
87 pr_warning("Cannot find set indentified by id %u to match\n",
88 info
->match_set
.index
);
91 if (info
->match_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
92 pr_warning("Protocol error: set match dimension "
93 "is over the limit!\n");
94 ip_set_nfnl_put(info
->match_set
.index
);
98 /* Fill out compatibility data */
99 compat_flags(&info
->match_set
);
105 set_match_v0_destroy(const struct xt_mtdtor_param
*par
)
107 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
109 ip_set_nfnl_put(info
->match_set
.index
);
113 set_target_v0(struct sk_buff
*skb
, const struct xt_action_param
*par
)
115 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
116 ADT_OPT(add_opt
, par
->family
, info
->add_set
.u
.compat
.dim
,
117 info
->add_set
.u
.compat
.flags
, 0, UINT_MAX
);
118 ADT_OPT(del_opt
, par
->family
, info
->del_set
.u
.compat
.dim
,
119 info
->del_set
.u
.compat
.flags
, 0, UINT_MAX
);
121 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
122 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
123 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
124 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
130 set_target_v0_checkentry(const struct xt_tgchk_param
*par
)
132 struct xt_set_info_target_v0
*info
= par
->targinfo
;
135 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
136 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
137 if (index
== IPSET_INVALID_ID
) {
138 pr_warning("Cannot find add_set index %u as target\n",
139 info
->add_set
.index
);
144 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
145 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
146 if (index
== IPSET_INVALID_ID
) {
147 pr_warning("Cannot find del_set index %u as target\n",
148 info
->del_set
.index
);
149 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
150 ip_set_nfnl_put(info
->add_set
.index
);
154 if (info
->add_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0 ||
155 info
->del_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
156 pr_warning("Protocol error: SET target dimension "
157 "is over the limit!\n");
158 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
159 ip_set_nfnl_put(info
->add_set
.index
);
160 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
161 ip_set_nfnl_put(info
->del_set
.index
);
165 /* Fill out compatibility data */
166 compat_flags(&info
->add_set
);
167 compat_flags(&info
->del_set
);
173 set_target_v0_destroy(const struct xt_tgdtor_param
*par
)
175 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
177 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
178 ip_set_nfnl_put(info
->add_set
.index
);
179 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
180 ip_set_nfnl_put(info
->del_set
.index
);
183 /* Revision 1 match and target */
186 set_match_v1(const struct sk_buff
*skb
, struct xt_action_param
*par
)
188 const struct xt_set_info_match_v1
*info
= par
->matchinfo
;
189 ADT_OPT(opt
, par
->family
, info
->match_set
.dim
,
190 info
->match_set
.flags
, 0, UINT_MAX
);
192 if (opt
.flags
& IPSET_RETURN_NOMATCH
)
193 opt
.cmdflags
|= IPSET_FLAG_RETURN_NOMATCH
;
195 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
196 info
->match_set
.flags
& IPSET_INV_MATCH
);
200 set_match_v1_checkentry(const struct xt_mtchk_param
*par
)
202 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
205 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
207 if (index
== IPSET_INVALID_ID
) {
208 pr_warning("Cannot find set indentified by id %u to match\n",
209 info
->match_set
.index
);
212 if (info
->match_set
.dim
> IPSET_DIM_MAX
) {
213 pr_warning("Protocol error: set match dimension "
214 "is over the limit!\n");
215 ip_set_nfnl_put(info
->match_set
.index
);
223 set_match_v1_destroy(const struct xt_mtdtor_param
*par
)
225 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
227 ip_set_nfnl_put(info
->match_set
.index
);
231 set_target_v1(struct sk_buff
*skb
, const struct xt_action_param
*par
)
233 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
234 ADT_OPT(add_opt
, par
->family
, info
->add_set
.dim
,
235 info
->add_set
.flags
, 0, UINT_MAX
);
236 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
237 info
->del_set
.flags
, 0, UINT_MAX
);
239 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
240 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
241 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
242 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
248 set_target_v1_checkentry(const struct xt_tgchk_param
*par
)
250 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
253 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
254 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
255 if (index
== IPSET_INVALID_ID
) {
256 pr_warning("Cannot find add_set index %u as target\n",
257 info
->add_set
.index
);
262 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
263 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
264 if (index
== IPSET_INVALID_ID
) {
265 pr_warning("Cannot find del_set index %u as target\n",
266 info
->del_set
.index
);
267 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
268 ip_set_nfnl_put(info
->add_set
.index
);
272 if (info
->add_set
.dim
> IPSET_DIM_MAX
||
273 info
->del_set
.dim
> IPSET_DIM_MAX
) {
274 pr_warning("Protocol error: SET target dimension "
275 "is over the limit!\n");
276 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
277 ip_set_nfnl_put(info
->add_set
.index
);
278 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
279 ip_set_nfnl_put(info
->del_set
.index
);
287 set_target_v1_destroy(const struct xt_tgdtor_param
*par
)
289 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
291 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
292 ip_set_nfnl_put(info
->add_set
.index
);
293 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
294 ip_set_nfnl_put(info
->del_set
.index
);
297 /* Revision 2 target */
300 set_target_v2(struct sk_buff
*skb
, const struct xt_action_param
*par
)
302 const struct xt_set_info_target_v2
*info
= par
->targinfo
;
303 ADT_OPT(add_opt
, par
->family
, info
->add_set
.dim
,
304 info
->add_set
.flags
, info
->flags
, info
->timeout
);
305 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
306 info
->del_set
.flags
, 0, UINT_MAX
);
308 /* Normalize to fit into jiffies */
309 if (add_opt
.ext
.timeout
!= IPSET_NO_TIMEOUT
&&
310 add_opt
.ext
.timeout
> UINT_MAX
/MSEC_PER_SEC
)
311 add_opt
.ext
.timeout
= UINT_MAX
/MSEC_PER_SEC
;
312 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
313 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
314 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
315 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
320 #define set_target_v2_checkentry set_target_v1_checkentry
321 #define set_target_v2_destroy set_target_v1_destroy
323 /* Revision 3 match */
326 match_counter(u64 counter
, const struct ip_set_counter_match
*info
)
329 case IPSET_COUNTER_NONE
:
331 case IPSET_COUNTER_EQ
:
332 return counter
== info
->value
;
333 case IPSET_COUNTER_NE
:
334 return counter
!= info
->value
;
335 case IPSET_COUNTER_LT
:
336 return counter
< info
->value
;
337 case IPSET_COUNTER_GT
:
338 return counter
> info
->value
;
344 set_match_v3(const struct sk_buff
*skb
, struct xt_action_param
*par
)
346 const struct xt_set_info_match_v3
*info
= par
->matchinfo
;
347 ADT_OPT(opt
, par
->family
, info
->match_set
.dim
,
348 info
->match_set
.flags
, info
->flags
, UINT_MAX
);
351 if (info
->packets
.op
!= IPSET_COUNTER_NONE
||
352 info
->bytes
.op
!= IPSET_COUNTER_NONE
)
353 opt
.cmdflags
|= IPSET_FLAG_MATCH_COUNTERS
;
355 ret
= match_set(info
->match_set
.index
, skb
, par
, &opt
,
356 info
->match_set
.flags
& IPSET_INV_MATCH
);
358 if (!(ret
&& opt
.cmdflags
& IPSET_FLAG_MATCH_COUNTERS
))
361 if (!match_counter(opt
.ext
.packets
, &info
->packets
))
363 return match_counter(opt
.ext
.bytes
, &info
->bytes
);
366 #define set_match_v3_checkentry set_match_v1_checkentry
367 #define set_match_v3_destroy set_match_v1_destroy
369 static struct xt_match set_matches
[] __read_mostly
= {
372 .family
= NFPROTO_IPV4
,
374 .match
= set_match_v0
,
375 .matchsize
= sizeof(struct xt_set_info_match_v0
),
376 .checkentry
= set_match_v0_checkentry
,
377 .destroy
= set_match_v0_destroy
,
382 .family
= NFPROTO_IPV4
,
384 .match
= set_match_v1
,
385 .matchsize
= sizeof(struct xt_set_info_match_v1
),
386 .checkentry
= set_match_v1_checkentry
,
387 .destroy
= set_match_v1_destroy
,
392 .family
= NFPROTO_IPV6
,
394 .match
= set_match_v1
,
395 .matchsize
= sizeof(struct xt_set_info_match_v1
),
396 .checkentry
= set_match_v1_checkentry
,
397 .destroy
= set_match_v1_destroy
,
400 /* --return-nomatch flag support */
403 .family
= NFPROTO_IPV4
,
405 .match
= set_match_v1
,
406 .matchsize
= sizeof(struct xt_set_info_match_v1
),
407 .checkentry
= set_match_v1_checkentry
,
408 .destroy
= set_match_v1_destroy
,
413 .family
= NFPROTO_IPV6
,
415 .match
= set_match_v1
,
416 .matchsize
= sizeof(struct xt_set_info_match_v1
),
417 .checkentry
= set_match_v1_checkentry
,
418 .destroy
= set_match_v1_destroy
,
421 /* counters support: update, match */
424 .family
= NFPROTO_IPV4
,
426 .match
= set_match_v3
,
427 .matchsize
= sizeof(struct xt_set_info_match_v3
),
428 .checkentry
= set_match_v3_checkentry
,
429 .destroy
= set_match_v3_destroy
,
434 .family
= NFPROTO_IPV6
,
436 .match
= set_match_v3
,
437 .matchsize
= sizeof(struct xt_set_info_match_v3
),
438 .checkentry
= set_match_v3_checkentry
,
439 .destroy
= set_match_v3_destroy
,
444 static struct xt_target set_targets
[] __read_mostly
= {
448 .family
= NFPROTO_IPV4
,
449 .target
= set_target_v0
,
450 .targetsize
= sizeof(struct xt_set_info_target_v0
),
451 .checkentry
= set_target_v0_checkentry
,
452 .destroy
= set_target_v0_destroy
,
458 .family
= NFPROTO_IPV4
,
459 .target
= set_target_v1
,
460 .targetsize
= sizeof(struct xt_set_info_target_v1
),
461 .checkentry
= set_target_v1_checkentry
,
462 .destroy
= set_target_v1_destroy
,
468 .family
= NFPROTO_IPV6
,
469 .target
= set_target_v1
,
470 .targetsize
= sizeof(struct xt_set_info_target_v1
),
471 .checkentry
= set_target_v1_checkentry
,
472 .destroy
= set_target_v1_destroy
,
475 /* --timeout and --exist flags support */
479 .family
= NFPROTO_IPV4
,
480 .target
= set_target_v2
,
481 .targetsize
= sizeof(struct xt_set_info_target_v2
),
482 .checkentry
= set_target_v2_checkentry
,
483 .destroy
= set_target_v2_destroy
,
489 .family
= NFPROTO_IPV6
,
490 .target
= set_target_v2
,
491 .targetsize
= sizeof(struct xt_set_info_target_v2
),
492 .checkentry
= set_target_v2_checkentry
,
493 .destroy
= set_target_v2_destroy
,
498 static int __init
xt_set_init(void)
500 int ret
= xt_register_matches(set_matches
, ARRAY_SIZE(set_matches
));
503 ret
= xt_register_targets(set_targets
,
504 ARRAY_SIZE(set_targets
));
506 xt_unregister_matches(set_matches
,
507 ARRAY_SIZE(set_matches
));
512 static void __exit
xt_set_fini(void)
514 xt_unregister_matches(set_matches
, ARRAY_SIZE(set_matches
));
515 xt_unregister_targets(set_targets
, ARRAY_SIZE(set_targets
));
518 module_init(xt_set_init
);
519 module_exit(xt_set_fini
);