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-2011 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>
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
22 MODULE_DESCRIPTION("Xtables: IP set match and target module");
23 MODULE_ALIAS("xt_SET");
24 MODULE_ALIAS("ipt_set");
25 MODULE_ALIAS("ip6t_set");
26 MODULE_ALIAS("ipt_SET");
27 MODULE_ALIAS("ip6t_SET");
30 match_set(ip_set_id_t index
, const struct sk_buff
*skb
,
31 const struct xt_action_param
*par
,
32 const struct ip_set_adt_opt
*opt
, int inv
)
34 if (ip_set_test(index
, skb
, par
, opt
))
39 #define ADT_OPT(n, f, d, fs, cfs, t) \
40 const struct ip_set_adt_opt n = { \
48 /* Revision 0 interface: backward compatible with netfilter/iptables */
51 set_match_v0(const struct sk_buff
*skb
, struct xt_action_param
*par
)
53 const struct xt_set_info_match_v0
*info
= par
->matchinfo
;
54 ADT_OPT(opt
, par
->family
, info
->match_set
.u
.compat
.dim
,
55 info
->match_set
.u
.compat
.flags
, 0, UINT_MAX
);
57 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
58 info
->match_set
.u
.compat
.flags
& IPSET_INV_MATCH
);
62 compat_flags(struct xt_set_info_v0
*info
)
66 /* Fill out compatibility data according to enum ip_set_kopt */
67 info
->u
.compat
.dim
= IPSET_DIM_ZERO
;
68 if (info
->u
.flags
[0] & IPSET_MATCH_INV
)
69 info
->u
.compat
.flags
|= IPSET_INV_MATCH
;
70 for (i
= 0; i
< IPSET_DIM_MAX
-1 && info
->u
.flags
[i
]; i
++) {
72 if (info
->u
.flags
[i
] & IPSET_SRC
)
73 info
->u
.compat
.flags
|= (1<<info
->u
.compat
.dim
);
78 set_match_v0_checkentry(const struct xt_mtchk_param
*par
)
80 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
83 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
85 if (index
== IPSET_INVALID_ID
) {
86 pr_warning("Cannot find set indentified by id %u to match\n",
87 info
->match_set
.index
);
90 if (info
->match_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
91 pr_warning("Protocol error: set match dimension "
92 "is over the limit!\n");
93 ip_set_nfnl_put(info
->match_set
.index
);
97 /* Fill out compatibility data */
98 compat_flags(&info
->match_set
);
104 set_match_v0_destroy(const struct xt_mtdtor_param
*par
)
106 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
108 ip_set_nfnl_put(info
->match_set
.index
);
112 set_target_v0(struct sk_buff
*skb
, const struct xt_action_param
*par
)
114 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
115 ADT_OPT(add_opt
, par
->family
, info
->add_set
.u
.compat
.dim
,
116 info
->add_set
.u
.compat
.flags
, 0, UINT_MAX
);
117 ADT_OPT(del_opt
, par
->family
, info
->del_set
.u
.compat
.dim
,
118 info
->del_set
.u
.compat
.flags
, 0, UINT_MAX
);
120 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
121 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
122 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
123 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
129 set_target_v0_checkentry(const struct xt_tgchk_param
*par
)
131 struct xt_set_info_target_v0
*info
= par
->targinfo
;
134 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
135 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
136 if (index
== IPSET_INVALID_ID
) {
137 pr_warning("Cannot find add_set index %u as target\n",
138 info
->add_set
.index
);
143 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
144 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
145 if (index
== IPSET_INVALID_ID
) {
146 pr_warning("Cannot find del_set index %u as target\n",
147 info
->del_set
.index
);
148 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
149 ip_set_nfnl_put(info
->add_set
.index
);
153 if (info
->add_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0 ||
154 info
->del_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
155 pr_warning("Protocol error: SET target dimension "
156 "is over the limit!\n");
157 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
158 ip_set_nfnl_put(info
->add_set
.index
);
159 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
160 ip_set_nfnl_put(info
->del_set
.index
);
164 /* Fill out compatibility data */
165 compat_flags(&info
->add_set
);
166 compat_flags(&info
->del_set
);
172 set_target_v0_destroy(const struct xt_tgdtor_param
*par
)
174 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
176 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
177 ip_set_nfnl_put(info
->add_set
.index
);
178 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
179 ip_set_nfnl_put(info
->del_set
.index
);
182 /* Revision 1 match and target */
185 set_match_v1(const struct sk_buff
*skb
, struct xt_action_param
*par
)
187 const struct xt_set_info_match_v1
*info
= par
->matchinfo
;
188 ADT_OPT(opt
, par
->family
, info
->match_set
.dim
,
189 info
->match_set
.flags
, 0, UINT_MAX
);
191 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
192 info
->match_set
.flags
& IPSET_INV_MATCH
);
196 set_match_v1_checkentry(const struct xt_mtchk_param
*par
)
198 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
201 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
203 if (index
== IPSET_INVALID_ID
) {
204 pr_warning("Cannot find set indentified by id %u to match\n",
205 info
->match_set
.index
);
208 if (info
->match_set
.dim
> IPSET_DIM_MAX
) {
209 pr_warning("Protocol error: set match dimension "
210 "is over the limit!\n");
211 ip_set_nfnl_put(info
->match_set
.index
);
219 set_match_v1_destroy(const struct xt_mtdtor_param
*par
)
221 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
223 ip_set_nfnl_put(info
->match_set
.index
);
227 set_target_v1(struct sk_buff
*skb
, const struct xt_action_param
*par
)
229 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
230 ADT_OPT(add_opt
, par
->family
, info
->add_set
.dim
,
231 info
->add_set
.flags
, 0, UINT_MAX
);
232 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
233 info
->del_set
.flags
, 0, UINT_MAX
);
235 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
236 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
237 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
238 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
244 set_target_v1_checkentry(const struct xt_tgchk_param
*par
)
246 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
249 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
250 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
251 if (index
== IPSET_INVALID_ID
) {
252 pr_warning("Cannot find add_set index %u as target\n",
253 info
->add_set
.index
);
258 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
259 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
260 if (index
== IPSET_INVALID_ID
) {
261 pr_warning("Cannot find del_set index %u as target\n",
262 info
->del_set
.index
);
263 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
264 ip_set_nfnl_put(info
->add_set
.index
);
268 if (info
->add_set
.dim
> IPSET_DIM_MAX
||
269 info
->del_set
.dim
> IPSET_DIM_MAX
) {
270 pr_warning("Protocol error: SET target dimension "
271 "is over the limit!\n");
272 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
273 ip_set_nfnl_put(info
->add_set
.index
);
274 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
275 ip_set_nfnl_put(info
->del_set
.index
);
283 set_target_v1_destroy(const struct xt_tgdtor_param
*par
)
285 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
287 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
288 ip_set_nfnl_put(info
->add_set
.index
);
289 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
290 ip_set_nfnl_put(info
->del_set
.index
);
293 /* Revision 2 target */
296 set_target_v2(struct sk_buff
*skb
, const struct xt_action_param
*par
)
298 const struct xt_set_info_target_v2
*info
= par
->targinfo
;
299 ADT_OPT(add_opt
, par
->family
, info
->add_set
.dim
,
300 info
->add_set
.flags
, info
->flags
, info
->timeout
);
301 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
302 info
->del_set
.flags
, 0, UINT_MAX
);
304 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
305 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
306 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
307 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
312 #define set_target_v2_checkentry set_target_v1_checkentry
313 #define set_target_v2_destroy set_target_v1_destroy
315 static struct xt_match set_matches
[] __read_mostly
= {
318 .family
= NFPROTO_IPV4
,
320 .match
= set_match_v0
,
321 .matchsize
= sizeof(struct xt_set_info_match_v0
),
322 .checkentry
= set_match_v0_checkentry
,
323 .destroy
= set_match_v0_destroy
,
328 .family
= NFPROTO_IPV4
,
330 .match
= set_match_v1
,
331 .matchsize
= sizeof(struct xt_set_info_match_v1
),
332 .checkentry
= set_match_v1_checkentry
,
333 .destroy
= set_match_v1_destroy
,
338 .family
= NFPROTO_IPV6
,
340 .match
= set_match_v1
,
341 .matchsize
= sizeof(struct xt_set_info_match_v1
),
342 .checkentry
= set_match_v1_checkentry
,
343 .destroy
= set_match_v1_destroy
,
348 static struct xt_target set_targets
[] __read_mostly
= {
352 .family
= NFPROTO_IPV4
,
353 .target
= set_target_v0
,
354 .targetsize
= sizeof(struct xt_set_info_target_v0
),
355 .checkentry
= set_target_v0_checkentry
,
356 .destroy
= set_target_v0_destroy
,
362 .family
= NFPROTO_IPV4
,
363 .target
= set_target_v1
,
364 .targetsize
= sizeof(struct xt_set_info_target_v1
),
365 .checkentry
= set_target_v1_checkentry
,
366 .destroy
= set_target_v1_destroy
,
372 .family
= NFPROTO_IPV6
,
373 .target
= set_target_v1
,
374 .targetsize
= sizeof(struct xt_set_info_target_v1
),
375 .checkentry
= set_target_v1_checkentry
,
376 .destroy
= set_target_v1_destroy
,
382 .family
= NFPROTO_IPV4
,
383 .target
= set_target_v2
,
384 .targetsize
= sizeof(struct xt_set_info_target_v2
),
385 .checkentry
= set_target_v2_checkentry
,
386 .destroy
= set_target_v2_destroy
,
392 .family
= NFPROTO_IPV6
,
393 .target
= set_target_v2
,
394 .targetsize
= sizeof(struct xt_set_info_target_v2
),
395 .checkentry
= set_target_v2_checkentry
,
396 .destroy
= set_target_v2_destroy
,
401 static int __init
xt_set_init(void)
403 int ret
= xt_register_matches(set_matches
, ARRAY_SIZE(set_matches
));
406 ret
= xt_register_targets(set_targets
,
407 ARRAY_SIZE(set_targets
));
409 xt_unregister_matches(set_matches
,
410 ARRAY_SIZE(set_matches
));
415 static void __exit
xt_set_fini(void)
417 xt_unregister_matches(set_matches
, ARRAY_SIZE(set_matches
));
418 xt_unregister_targets(set_targets
, ARRAY_SIZE(set_targets
));
421 module_init(xt_set_init
);
422 module_exit(xt_set_fini
);