aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-02-01 09:56:00 -0500
committerPatrick McHardy <kaber@trash.net>2011-02-01 09:56:00 -0500
commitd956798d82d2d331c031301965d69e17a1a48a2b (patch)
tree3ceb434334d79d9dd8b205fc502cf2d20ab737ab /net
parentf830837f0eed0f9e371b8fd65169365780814bb1 (diff)
netfilter: xtables: "set" match and "SET" target support
The patch adds the combined module of the "SET" target and "set" match to netfilter. Both the previous and the current revisions are supported. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/Kconfig12
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/xt_set.c359
3 files changed, 372 insertions, 0 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 351abf8ace13..06fa9e4e45c7 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -352,6 +352,18 @@ config NETFILTER_XT_CONNMARK
352 ctmark), similarly to the packet mark (nfmark). Using this 352 ctmark), similarly to the packet mark (nfmark). Using this
353 target and match, you can set and match on this mark. 353 target and match, you can set and match on this mark.
354 354
355config NETFILTER_XT_SET
356 tristate 'set target and match support'
357 depends on IP_SET
358 depends on NETFILTER_ADVANCED
359 help
360 This option adds the "SET" target and "set" match.
361
362 Using this target and match, you can add/delete and match
363 elements in the sets created by ipset(8).
364
365 To compile it as a module, choose M here. If unsure, say N.
366
355# alphabetically ordered list of targets 367# alphabetically ordered list of targets
356 368
357comment "Xtables targets" 369comment "Xtables targets"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 510b586ccb7f..1148643559cb 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
46# combos 46# combos
47obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o 47obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o
48obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o 48obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o
49obj-$(CONFIG_NETFILTER_XT_SET) += xt_set.o
49 50
50# targets 51# targets
51obj-$(CONFIG_NETFILTER_XT_TARGET_AUDIT) += xt_AUDIT.o 52obj-$(CONFIG_NETFILTER_XT_TARGET_AUDIT) += xt_AUDIT.o
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
new file mode 100644
index 000000000000..061d48cec137
--- /dev/null
+++ b/net/netfilter/xt_set.c
@@ -0,0 +1,359 @@
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>
5 *
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.
9 */
10
11/* Kernel module which implements the set match and SET target
12 * for netfilter/iptables. */
13
14#include <linux/module.h>
15#include <linux/skbuff.h>
16#include <linux/version.h>
17
18#include <linux/netfilter/x_tables.h>
19#include <linux/netfilter/xt_set.h>
20
21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
23MODULE_DESCRIPTION("Xtables: IP set match and target module");
24MODULE_ALIAS("xt_SET");
25MODULE_ALIAS("ipt_set");
26MODULE_ALIAS("ip6t_set");
27MODULE_ALIAS("ipt_SET");
28MODULE_ALIAS("ip6t_SET");
29
30static inline int
31match_set(ip_set_id_t index, const struct sk_buff *skb,
32 u8 pf, u8 dim, u8 flags, int inv)
33{
34 if (ip_set_test(index, skb, pf, dim, flags))
35 inv = !inv;
36 return inv;
37}
38
39/* Revision 0 interface: backward compatible with netfilter/iptables */
40
41static bool
42set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
43{
44 const struct xt_set_info_match_v0 *info = par->matchinfo;
45
46 return match_set(info->match_set.index, skb, par->family,
47 info->match_set.u.compat.dim,
48 info->match_set.u.compat.flags,
49 info->match_set.u.compat.flags & IPSET_INV_MATCH);
50}
51
52static void
53compat_flags(struct xt_set_info_v0 *info)
54{
55 u_int8_t i;
56
57 /* Fill out compatibility data according to enum ip_set_kopt */
58 info->u.compat.dim = IPSET_DIM_ZERO;
59 if (info->u.flags[0] & IPSET_MATCH_INV)
60 info->u.compat.flags |= IPSET_INV_MATCH;
61 for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
62 info->u.compat.dim++;
63 if (info->u.flags[i] & IPSET_SRC)
64 info->u.compat.flags |= (1<<info->u.compat.dim);
65 }
66}
67
68static int
69set_match_v0_checkentry(const struct xt_mtchk_param *par)
70{
71 struct xt_set_info_match_v0 *info = par->matchinfo;
72 ip_set_id_t index;
73
74 index = ip_set_nfnl_get_byindex(info->match_set.index);
75
76 if (index == IPSET_INVALID_ID) {
77 pr_warning("Cannot find set indentified by id %u to match\n",
78 info->match_set.index);
79 return -ENOENT;
80 }
81 if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
82 pr_warning("Protocol error: set match dimension "
83 "is over the limit!\n");
84 return -ERANGE;
85 }
86
87 /* Fill out compatibility data */
88 compat_flags(&info->match_set);
89
90 return 0;
91}
92
93static void
94set_match_v0_destroy(const struct xt_mtdtor_param *par)
95{
96 struct xt_set_info_match_v0 *info = par->matchinfo;
97
98 ip_set_nfnl_put(info->match_set.index);
99}
100
101static unsigned int
102set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
103{
104 const struct xt_set_info_target_v0 *info = par->targinfo;
105
106 if (info->add_set.index != IPSET_INVALID_ID)
107 ip_set_add(info->add_set.index, skb, par->family,
108 info->add_set.u.compat.dim,
109 info->add_set.u.compat.flags);
110 if (info->del_set.index != IPSET_INVALID_ID)
111 ip_set_del(info->del_set.index, skb, par->family,
112 info->del_set.u.compat.dim,
113 info->del_set.u.compat.flags);
114
115 return XT_CONTINUE;
116}
117
118static int
119set_target_v0_checkentry(const struct xt_tgchk_param *par)
120{
121 struct xt_set_info_target_v0 *info = par->targinfo;
122 ip_set_id_t index;
123
124 if (info->add_set.index != IPSET_INVALID_ID) {
125 index = ip_set_nfnl_get_byindex(info->add_set.index);
126 if (index == IPSET_INVALID_ID) {
127 pr_warning("Cannot find add_set index %u as target\n",
128 info->add_set.index);
129 return -ENOENT;
130 }
131 }
132
133 if (info->del_set.index != IPSET_INVALID_ID) {
134 index = ip_set_nfnl_get_byindex(info->del_set.index);
135 if (index == IPSET_INVALID_ID) {
136 pr_warning("Cannot find del_set index %u as target\n",
137 info->del_set.index);
138 return -ENOENT;
139 }
140 }
141 if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
142 info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
143 pr_warning("Protocol error: SET target dimension "
144 "is over the limit!\n");
145 return -ERANGE;
146 }
147
148 /* Fill out compatibility data */
149 compat_flags(&info->add_set);
150 compat_flags(&info->del_set);
151
152 return 0;
153}
154
155static void
156set_target_v0_destroy(const struct xt_tgdtor_param *par)
157{
158 const struct xt_set_info_target_v0 *info = par->targinfo;
159
160 if (info->add_set.index != IPSET_INVALID_ID)
161 ip_set_nfnl_put(info->add_set.index);
162 if (info->del_set.index != IPSET_INVALID_ID)
163 ip_set_nfnl_put(info->del_set.index);
164}
165
166/* Revision 1: current interface to netfilter/iptables */
167
168static bool
169set_match(const struct sk_buff *skb, struct xt_action_param *par)
170{
171 const struct xt_set_info_match *info = par->matchinfo;
172
173 return match_set(info->match_set.index, skb, par->family,
174 info->match_set.dim,
175 info->match_set.flags,
176 info->match_set.flags & IPSET_INV_MATCH);
177}
178
179static int
180set_match_checkentry(const struct xt_mtchk_param *par)
181{
182 struct xt_set_info_match *info = par->matchinfo;
183 ip_set_id_t index;
184
185 index = ip_set_nfnl_get_byindex(info->match_set.index);
186
187 if (index == IPSET_INVALID_ID) {
188 pr_warning("Cannot find set indentified by id %u to match\n",
189 info->match_set.index);
190 return -ENOENT;
191 }
192 if (info->match_set.dim > IPSET_DIM_MAX) {
193 pr_warning("Protocol error: set match dimension "
194 "is over the limit!\n");
195 return -ERANGE;
196 }
197
198 return 0;
199}
200
201static void
202set_match_destroy(const struct xt_mtdtor_param *par)
203{
204 struct xt_set_info_match *info = par->matchinfo;
205
206 ip_set_nfnl_put(info->match_set.index);
207}
208
209static unsigned int
210set_target(struct sk_buff *skb, const struct xt_action_param *par)
211{
212 const struct xt_set_info_target *info = par->targinfo;
213
214 if (info->add_set.index != IPSET_INVALID_ID)
215 ip_set_add(info->add_set.index,
216 skb, par->family,
217 info->add_set.dim,
218 info->add_set.flags);
219 if (info->del_set.index != IPSET_INVALID_ID)
220 ip_set_del(info->del_set.index,
221 skb, par->family,
222 info->add_set.dim,
223 info->del_set.flags);
224
225 return XT_CONTINUE;
226}
227
228static int
229set_target_checkentry(const struct xt_tgchk_param *par)
230{
231 const struct xt_set_info_target *info = par->targinfo;
232 ip_set_id_t index;
233
234 if (info->add_set.index != IPSET_INVALID_ID) {
235 index = ip_set_nfnl_get_byindex(info->add_set.index);
236 if (index == IPSET_INVALID_ID) {
237 pr_warning("Cannot find add_set index %u as target\n",
238 info->add_set.index);
239 return -ENOENT;
240 }
241 }
242
243 if (info->del_set.index != IPSET_INVALID_ID) {
244 index = ip_set_nfnl_get_byindex(info->del_set.index);
245 if (index == IPSET_INVALID_ID) {
246 pr_warning("Cannot find del_set index %u as target\n",
247 info->del_set.index);
248 return -ENOENT;
249 }
250 }
251 if (info->add_set.dim > IPSET_DIM_MAX ||
252 info->del_set.flags > IPSET_DIM_MAX) {
253 pr_warning("Protocol error: SET target dimension "
254 "is over the limit!\n");
255 return -ERANGE;
256 }
257
258 return 0;
259}
260
261static void
262set_target_destroy(const struct xt_tgdtor_param *par)
263{
264 const struct xt_set_info_target *info = par->targinfo;
265
266 if (info->add_set.index != IPSET_INVALID_ID)
267 ip_set_nfnl_put(info->add_set.index);
268 if (info->del_set.index != IPSET_INVALID_ID)
269 ip_set_nfnl_put(info->del_set.index);
270}
271
272static struct xt_match set_matches[] __read_mostly = {
273 {
274 .name = "set",
275 .family = NFPROTO_IPV4,
276 .revision = 0,
277 .match = set_match_v0,
278 .matchsize = sizeof(struct xt_set_info_match_v0),
279 .checkentry = set_match_v0_checkentry,
280 .destroy = set_match_v0_destroy,
281 .me = THIS_MODULE
282 },
283 {
284 .name = "set",
285 .family = NFPROTO_IPV4,
286 .revision = 1,
287 .match = set_match,
288 .matchsize = sizeof(struct xt_set_info_match),
289 .checkentry = set_match_checkentry,
290 .destroy = set_match_destroy,
291 .me = THIS_MODULE
292 },
293 {
294 .name = "set",
295 .family = NFPROTO_IPV6,
296 .revision = 1,
297 .match = set_match,
298 .matchsize = sizeof(struct xt_set_info_match),
299 .checkentry = set_match_checkentry,
300 .destroy = set_match_destroy,
301 .me = THIS_MODULE
302 },
303};
304
305static struct xt_target set_targets[] __read_mostly = {
306 {
307 .name = "SET",
308 .revision = 0,
309 .family = NFPROTO_IPV4,
310 .target = set_target_v0,
311 .targetsize = sizeof(struct xt_set_info_target_v0),
312 .checkentry = set_target_v0_checkentry,
313 .destroy = set_target_v0_destroy,
314 .me = THIS_MODULE
315 },
316 {
317 .name = "SET",
318 .revision = 1,
319 .family = NFPROTO_IPV4,
320 .target = set_target,
321 .targetsize = sizeof(struct xt_set_info_target),
322 .checkentry = set_target_checkentry,
323 .destroy = set_target_destroy,
324 .me = THIS_MODULE
325 },
326 {
327 .name = "SET",
328 .revision = 1,
329 .family = NFPROTO_IPV6,
330 .target = set_target,
331 .targetsize = sizeof(struct xt_set_info_target),
332 .checkentry = set_target_checkentry,
333 .destroy = set_target_destroy,
334 .me = THIS_MODULE
335 },
336};
337
338static int __init xt_set_init(void)
339{
340 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
341
342 if (!ret) {
343 ret = xt_register_targets(set_targets,
344 ARRAY_SIZE(set_targets));
345 if (ret)
346 xt_unregister_matches(set_matches,
347 ARRAY_SIZE(set_matches));
348 }
349 return ret;
350}
351
352static void __exit xt_set_fini(void)
353{
354 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
355 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
356}
357
358module_init(xt_set_init);
359module_exit(xt_set_fini);