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>
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 const 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 const struct ip_set_adt_opt n = { \
48 #define ADT_MOPT(n, f, d, fs, cfs, t) \
49 struct ip_set_adt_opt n = { \
57 /* Revision 0 interface: backward compatible with netfilter/iptables */
60 set_match_v0(const struct sk_buff
*skb
, struct xt_action_param
*par
)
62 const struct xt_set_info_match_v0
*info
= par
->matchinfo
;
63 ADT_OPT(opt
, par
->family
, info
->match_set
.u
.compat
.dim
,
64 info
->match_set
.u
.compat
.flags
, 0, UINT_MAX
);
66 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
67 info
->match_set
.u
.compat
.flags
& IPSET_INV_MATCH
);
71 compat_flags(struct xt_set_info_v0
*info
)
75 /* Fill out compatibility data according to enum ip_set_kopt */
76 info
->u
.compat
.dim
= IPSET_DIM_ZERO
;
77 if (info
->u
.flags
[0] & IPSET_MATCH_INV
)
78 info
->u
.compat
.flags
|= IPSET_INV_MATCH
;
79 for (i
= 0; i
< IPSET_DIM_MAX
-1 && info
->u
.flags
[i
]; i
++) {
81 if (info
->u
.flags
[i
] & IPSET_SRC
)
82 info
->u
.compat
.flags
|= (1<<info
->u
.compat
.dim
);
87 set_match_v0_checkentry(const struct xt_mtchk_param
*par
)
89 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
92 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
94 if (index
== IPSET_INVALID_ID
) {
95 pr_warning("Cannot find set indentified by id %u to match\n",
96 info
->match_set
.index
);
99 if (info
->match_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
100 pr_warning("Protocol error: set match dimension "
101 "is over the limit!\n");
102 ip_set_nfnl_put(info
->match_set
.index
);
106 /* Fill out compatibility data */
107 compat_flags(&info
->match_set
);
113 set_match_v0_destroy(const struct xt_mtdtor_param
*par
)
115 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
117 ip_set_nfnl_put(info
->match_set
.index
);
121 set_target_v0(struct sk_buff
*skb
, const struct xt_action_param
*par
)
123 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
124 ADT_OPT(add_opt
, par
->family
, info
->add_set
.u
.compat
.dim
,
125 info
->add_set
.u
.compat
.flags
, 0, UINT_MAX
);
126 ADT_OPT(del_opt
, par
->family
, info
->del_set
.u
.compat
.dim
,
127 info
->del_set
.u
.compat
.flags
, 0, UINT_MAX
);
129 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
130 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
131 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
132 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
138 set_target_v0_checkentry(const struct xt_tgchk_param
*par
)
140 struct xt_set_info_target_v0
*info
= par
->targinfo
;
143 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
144 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
145 if (index
== IPSET_INVALID_ID
) {
146 pr_warning("Cannot find add_set index %u as target\n",
147 info
->add_set
.index
);
152 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
153 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
154 if (index
== IPSET_INVALID_ID
) {
155 pr_warning("Cannot find del_set index %u as target\n",
156 info
->del_set
.index
);
157 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
158 ip_set_nfnl_put(info
->add_set
.index
);
162 if (info
->add_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0 ||
163 info
->del_set
.u
.flags
[IPSET_DIM_MAX
-1] != 0) {
164 pr_warning("Protocol error: SET target dimension "
165 "is over the limit!\n");
166 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
167 ip_set_nfnl_put(info
->add_set
.index
);
168 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
169 ip_set_nfnl_put(info
->del_set
.index
);
173 /* Fill out compatibility data */
174 compat_flags(&info
->add_set
);
175 compat_flags(&info
->del_set
);
181 set_target_v0_destroy(const struct xt_tgdtor_param
*par
)
183 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
185 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
186 ip_set_nfnl_put(info
->add_set
.index
);
187 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
188 ip_set_nfnl_put(info
->del_set
.index
);
191 /* Revision 1 match and target */
194 set_match_v1(const struct sk_buff
*skb
, struct xt_action_param
*par
)
196 const struct xt_set_info_match_v1
*info
= par
->matchinfo
;
197 ADT_OPT(opt
, par
->family
, info
->match_set
.dim
,
198 info
->match_set
.flags
, 0, UINT_MAX
);
200 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
201 info
->match_set
.flags
& IPSET_INV_MATCH
);
205 set_match_v1_checkentry(const struct xt_mtchk_param
*par
)
207 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
210 index
= ip_set_nfnl_get_byindex(info
->match_set
.index
);
212 if (index
== IPSET_INVALID_ID
) {
213 pr_warning("Cannot find set indentified by id %u to match\n",
214 info
->match_set
.index
);
217 if (info
->match_set
.dim
> IPSET_DIM_MAX
) {
218 pr_warning("Protocol error: set match dimension "
219 "is over the limit!\n");
220 ip_set_nfnl_put(info
->match_set
.index
);
228 set_match_v1_destroy(const struct xt_mtdtor_param
*par
)
230 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
232 ip_set_nfnl_put(info
->match_set
.index
);
236 set_target_v1(struct sk_buff
*skb
, const struct xt_action_param
*par
)
238 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
239 ADT_OPT(add_opt
, par
->family
, info
->add_set
.dim
,
240 info
->add_set
.flags
, 0, UINT_MAX
);
241 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
242 info
->del_set
.flags
, 0, UINT_MAX
);
244 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
245 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
246 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
247 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
253 set_target_v1_checkentry(const struct xt_tgchk_param
*par
)
255 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
258 if (info
->add_set
.index
!= IPSET_INVALID_ID
) {
259 index
= ip_set_nfnl_get_byindex(info
->add_set
.index
);
260 if (index
== IPSET_INVALID_ID
) {
261 pr_warning("Cannot find add_set index %u as target\n",
262 info
->add_set
.index
);
267 if (info
->del_set
.index
!= IPSET_INVALID_ID
) {
268 index
= ip_set_nfnl_get_byindex(info
->del_set
.index
);
269 if (index
== IPSET_INVALID_ID
) {
270 pr_warning("Cannot find del_set index %u as target\n",
271 info
->del_set
.index
);
272 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
273 ip_set_nfnl_put(info
->add_set
.index
);
277 if (info
->add_set
.dim
> IPSET_DIM_MAX
||
278 info
->del_set
.dim
> IPSET_DIM_MAX
) {
279 pr_warning("Protocol error: SET target dimension "
280 "is over the limit!\n");
281 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
282 ip_set_nfnl_put(info
->add_set
.index
);
283 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
284 ip_set_nfnl_put(info
->del_set
.index
);
292 set_target_v1_destroy(const struct xt_tgdtor_param
*par
)
294 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
296 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
297 ip_set_nfnl_put(info
->add_set
.index
);
298 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
299 ip_set_nfnl_put(info
->del_set
.index
);
302 /* Revision 2 target */
305 set_target_v2(struct sk_buff
*skb
, const struct xt_action_param
*par
)
307 const struct xt_set_info_target_v2
*info
= par
->targinfo
;
308 ADT_MOPT(add_opt
, par
->family
, info
->add_set
.dim
,
309 info
->add_set
.flags
, info
->flags
, info
->timeout
);
310 ADT_OPT(del_opt
, par
->family
, info
->del_set
.dim
,
311 info
->del_set
.flags
, 0, UINT_MAX
);
313 /* Normalize to fit into jiffies */
314 if (add_opt
.timeout
!= IPSET_NO_TIMEOUT
&&
315 add_opt
.timeout
> UINT_MAX
/MSEC_PER_SEC
)
316 add_opt
.timeout
= UINT_MAX
/MSEC_PER_SEC
;
317 if (info
->add_set
.index
!= IPSET_INVALID_ID
)
318 ip_set_add(info
->add_set
.index
, skb
, par
, &add_opt
);
319 if (info
->del_set
.index
!= IPSET_INVALID_ID
)
320 ip_set_del(info
->del_set
.index
, skb
, par
, &del_opt
);
325 #define set_target_v2_checkentry set_target_v1_checkentry
326 #define set_target_v2_destroy set_target_v1_destroy
328 static struct xt_match set_matches
[] __read_mostly
= {
331 .family
= NFPROTO_IPV4
,
333 .match
= set_match_v0
,
334 .matchsize
= sizeof(struct xt_set_info_match_v0
),
335 .checkentry
= set_match_v0_checkentry
,
336 .destroy
= set_match_v0_destroy
,
341 .family
= NFPROTO_IPV4
,
343 .match
= set_match_v1
,
344 .matchsize
= sizeof(struct xt_set_info_match_v1
),
345 .checkentry
= set_match_v1_checkentry
,
346 .destroy
= set_match_v1_destroy
,
351 .family
= NFPROTO_IPV6
,
353 .match
= set_match_v1
,
354 .matchsize
= sizeof(struct xt_set_info_match_v1
),
355 .checkentry
= set_match_v1_checkentry
,
356 .destroy
= set_match_v1_destroy
,
359 /* --return-nomatch flag support */
362 .family
= NFPROTO_IPV4
,
364 .match
= set_match_v1
,
365 .matchsize
= sizeof(struct xt_set_info_match_v1
),
366 .checkentry
= set_match_v1_checkentry
,
367 .destroy
= set_match_v1_destroy
,
372 .family
= NFPROTO_IPV6
,
374 .match
= set_match_v1
,
375 .matchsize
= sizeof(struct xt_set_info_match_v1
),
376 .checkentry
= set_match_v1_checkentry
,
377 .destroy
= set_match_v1_destroy
,
382 static struct xt_target set_targets
[] __read_mostly
= {
386 .family
= NFPROTO_IPV4
,
387 .target
= set_target_v0
,
388 .targetsize
= sizeof(struct xt_set_info_target_v0
),
389 .checkentry
= set_target_v0_checkentry
,
390 .destroy
= set_target_v0_destroy
,
396 .family
= NFPROTO_IPV4
,
397 .target
= set_target_v1
,
398 .targetsize
= sizeof(struct xt_set_info_target_v1
),
399 .checkentry
= set_target_v1_checkentry
,
400 .destroy
= set_target_v1_destroy
,
406 .family
= NFPROTO_IPV6
,
407 .target
= set_target_v1
,
408 .targetsize
= sizeof(struct xt_set_info_target_v1
),
409 .checkentry
= set_target_v1_checkentry
,
410 .destroy
= set_target_v1_destroy
,
413 /* --timeout and --exist flags support */
417 .family
= NFPROTO_IPV4
,
418 .target
= set_target_v2
,
419 .targetsize
= sizeof(struct xt_set_info_target_v2
),
420 .checkentry
= set_target_v2_checkentry
,
421 .destroy
= set_target_v2_destroy
,
427 .family
= NFPROTO_IPV6
,
428 .target
= set_target_v2
,
429 .targetsize
= sizeof(struct xt_set_info_target_v2
),
430 .checkentry
= set_target_v2_checkentry
,
431 .destroy
= set_target_v2_destroy
,
436 static int __init
xt_set_init(void)
438 int ret
= xt_register_matches(set_matches
, ARRAY_SIZE(set_matches
));
441 ret
= xt_register_targets(set_targets
,
442 ARRAY_SIZE(set_targets
));
444 xt_unregister_matches(set_matches
,
445 ARRAY_SIZE(set_matches
));
450 static void __exit
xt_set_fini(void)
452 xt_unregister_matches(set_matches
, ARRAY_SIZE(set_matches
));
453 xt_unregister_targets(set_targets
, ARRAY_SIZE(set_targets
));
456 module_init(xt_set_init
);
457 module_exit(xt_set_fini
);