xref: /openbmc/linux/net/netfilter/xt_set.c (revision efe4a1ac)
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>
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 
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
17 
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter/ipset/ip_set.h>
20 #include <linux/netfilter/ipset/ip_set_timeout.h>
21 #include <uapi/linux/netfilter/xt_set.h>
22 
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25 MODULE_DESCRIPTION("Xtables: IP set match and target module");
26 MODULE_ALIAS("xt_SET");
27 MODULE_ALIAS("ipt_set");
28 MODULE_ALIAS("ip6t_set");
29 MODULE_ALIAS("ipt_SET");
30 MODULE_ALIAS("ip6t_SET");
31 
32 static inline int
33 match_set(ip_set_id_t index, const struct sk_buff *skb,
34 	  const struct xt_action_param *par,
35 	  struct ip_set_adt_opt *opt, int inv)
36 {
37 	if (ip_set_test(index, skb, par, opt))
38 		inv = !inv;
39 	return inv;
40 }
41 
42 #define ADT_OPT(n, f, d, fs, cfs, t)	\
43 struct ip_set_adt_opt n = {		\
44 	.family	= f,			\
45 	.dim = d,			\
46 	.flags = fs,			\
47 	.cmdflags = cfs,		\
48 	.ext.timeout = t,		\
49 }
50 
51 /* Revision 0 interface: backward compatible with netfilter/iptables */
52 
53 static bool
54 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
55 {
56 	const struct xt_set_info_match_v0 *info = par->matchinfo;
57 
58 	ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
59 		info->match_set.u.compat.flags, 0, UINT_MAX);
60 
61 	return match_set(info->match_set.index, skb, par, &opt,
62 			 info->match_set.u.compat.flags & IPSET_INV_MATCH);
63 }
64 
65 static void
66 compat_flags(struct xt_set_info_v0 *info)
67 {
68 	u_int8_t i;
69 
70 	/* Fill out compatibility data according to enum ip_set_kopt */
71 	info->u.compat.dim = IPSET_DIM_ZERO;
72 	if (info->u.flags[0] & IPSET_MATCH_INV)
73 		info->u.compat.flags |= IPSET_INV_MATCH;
74 	for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
75 		info->u.compat.dim++;
76 		if (info->u.flags[i] & IPSET_SRC)
77 			info->u.compat.flags |= (1 << info->u.compat.dim);
78 	}
79 }
80 
81 static int
82 set_match_v0_checkentry(const struct xt_mtchk_param *par)
83 {
84 	struct xt_set_info_match_v0 *info = par->matchinfo;
85 	ip_set_id_t index;
86 
87 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
88 
89 	if (index == IPSET_INVALID_ID) {
90 		pr_warn("Cannot find set identified by id %u to match\n",
91 			info->match_set.index);
92 		return -ENOENT;
93 	}
94 	if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
95 		pr_warn("Protocol error: set match dimension is over the limit!\n");
96 		ip_set_nfnl_put(par->net, info->match_set.index);
97 		return -ERANGE;
98 	}
99 
100 	/* Fill out compatibility data */
101 	compat_flags(&info->match_set);
102 
103 	return 0;
104 }
105 
106 static void
107 set_match_v0_destroy(const struct xt_mtdtor_param *par)
108 {
109 	struct xt_set_info_match_v0 *info = par->matchinfo;
110 
111 	ip_set_nfnl_put(par->net, info->match_set.index);
112 }
113 
114 /* Revision 1 match */
115 
116 static bool
117 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
118 {
119 	const struct xt_set_info_match_v1 *info = par->matchinfo;
120 
121 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
122 		info->match_set.flags, 0, UINT_MAX);
123 
124 	if (opt.flags & IPSET_RETURN_NOMATCH)
125 		opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
126 
127 	return match_set(info->match_set.index, skb, par, &opt,
128 			 info->match_set.flags & IPSET_INV_MATCH);
129 }
130 
131 static int
132 set_match_v1_checkentry(const struct xt_mtchk_param *par)
133 {
134 	struct xt_set_info_match_v1 *info = par->matchinfo;
135 	ip_set_id_t index;
136 
137 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
138 
139 	if (index == IPSET_INVALID_ID) {
140 		pr_warn("Cannot find set identified by id %u to match\n",
141 			info->match_set.index);
142 		return -ENOENT;
143 	}
144 	if (info->match_set.dim > IPSET_DIM_MAX) {
145 		pr_warn("Protocol error: set match dimension is over the limit!\n");
146 		ip_set_nfnl_put(par->net, info->match_set.index);
147 		return -ERANGE;
148 	}
149 
150 	return 0;
151 }
152 
153 static void
154 set_match_v1_destroy(const struct xt_mtdtor_param *par)
155 {
156 	struct xt_set_info_match_v1 *info = par->matchinfo;
157 
158 	ip_set_nfnl_put(par->net, info->match_set.index);
159 }
160 
161 /* Revision 3 match */
162 
163 static bool
164 match_counter0(u64 counter, const struct ip_set_counter_match0 *info)
165 {
166 	switch (info->op) {
167 	case IPSET_COUNTER_NONE:
168 		return true;
169 	case IPSET_COUNTER_EQ:
170 		return counter == info->value;
171 	case IPSET_COUNTER_NE:
172 		return counter != info->value;
173 	case IPSET_COUNTER_LT:
174 		return counter < info->value;
175 	case IPSET_COUNTER_GT:
176 		return counter > info->value;
177 	}
178 	return false;
179 }
180 
181 static bool
182 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
183 {
184 	const struct xt_set_info_match_v3 *info = par->matchinfo;
185 	int ret;
186 
187 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
188 		info->match_set.flags, info->flags, UINT_MAX);
189 
190 	if (info->packets.op != IPSET_COUNTER_NONE ||
191 	    info->bytes.op != IPSET_COUNTER_NONE)
192 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
193 
194 	ret = match_set(info->match_set.index, skb, par, &opt,
195 			info->match_set.flags & IPSET_INV_MATCH);
196 
197 	if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
198 		return ret;
199 
200 	if (!match_counter0(opt.ext.packets, &info->packets))
201 		return false;
202 	return match_counter0(opt.ext.bytes, &info->bytes);
203 }
204 
205 #define set_match_v3_checkentry	set_match_v1_checkentry
206 #define set_match_v3_destroy	set_match_v1_destroy
207 
208 /* Revision 4 match */
209 
210 static bool
211 match_counter(u64 counter, const struct ip_set_counter_match *info)
212 {
213 	switch (info->op) {
214 	case IPSET_COUNTER_NONE:
215 		return true;
216 	case IPSET_COUNTER_EQ:
217 		return counter == info->value;
218 	case IPSET_COUNTER_NE:
219 		return counter != info->value;
220 	case IPSET_COUNTER_LT:
221 		return counter < info->value;
222 	case IPSET_COUNTER_GT:
223 		return counter > info->value;
224 	}
225 	return false;
226 }
227 
228 static bool
229 set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
230 {
231 	const struct xt_set_info_match_v4 *info = par->matchinfo;
232 	int ret;
233 
234 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
235 		info->match_set.flags, info->flags, UINT_MAX);
236 
237 	if (info->packets.op != IPSET_COUNTER_NONE ||
238 	    info->bytes.op != IPSET_COUNTER_NONE)
239 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
240 
241 	ret = match_set(info->match_set.index, skb, par, &opt,
242 			info->match_set.flags & IPSET_INV_MATCH);
243 
244 	if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
245 		return ret;
246 
247 	if (!match_counter(opt.ext.packets, &info->packets))
248 		return false;
249 	return match_counter(opt.ext.bytes, &info->bytes);
250 }
251 
252 #define set_match_v4_checkentry	set_match_v1_checkentry
253 #define set_match_v4_destroy	set_match_v1_destroy
254 
255 /* Revision 0 interface: backward compatible with netfilter/iptables */
256 
257 static unsigned int
258 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
259 {
260 	const struct xt_set_info_target_v0 *info = par->targinfo;
261 
262 	ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
263 		info->add_set.u.compat.flags, 0, UINT_MAX);
264 	ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
265 		info->del_set.u.compat.flags, 0, UINT_MAX);
266 
267 	if (info->add_set.index != IPSET_INVALID_ID)
268 		ip_set_add(info->add_set.index, skb, par, &add_opt);
269 	if (info->del_set.index != IPSET_INVALID_ID)
270 		ip_set_del(info->del_set.index, skb, par, &del_opt);
271 
272 	return XT_CONTINUE;
273 }
274 
275 static int
276 set_target_v0_checkentry(const struct xt_tgchk_param *par)
277 {
278 	struct xt_set_info_target_v0 *info = par->targinfo;
279 	ip_set_id_t index;
280 
281 	if (info->add_set.index != IPSET_INVALID_ID) {
282 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
283 		if (index == IPSET_INVALID_ID) {
284 			pr_warn("Cannot find add_set index %u as target\n",
285 				info->add_set.index);
286 			return -ENOENT;
287 		}
288 	}
289 
290 	if (info->del_set.index != IPSET_INVALID_ID) {
291 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
292 		if (index == IPSET_INVALID_ID) {
293 			pr_warn("Cannot find del_set index %u as target\n",
294 				info->del_set.index);
295 			if (info->add_set.index != IPSET_INVALID_ID)
296 				ip_set_nfnl_put(par->net, info->add_set.index);
297 			return -ENOENT;
298 		}
299 	}
300 	if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
301 	    info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
302 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
303 		if (info->add_set.index != IPSET_INVALID_ID)
304 			ip_set_nfnl_put(par->net, info->add_set.index);
305 		if (info->del_set.index != IPSET_INVALID_ID)
306 			ip_set_nfnl_put(par->net, info->del_set.index);
307 		return -ERANGE;
308 	}
309 
310 	/* Fill out compatibility data */
311 	compat_flags(&info->add_set);
312 	compat_flags(&info->del_set);
313 
314 	return 0;
315 }
316 
317 static void
318 set_target_v0_destroy(const struct xt_tgdtor_param *par)
319 {
320 	const struct xt_set_info_target_v0 *info = par->targinfo;
321 
322 	if (info->add_set.index != IPSET_INVALID_ID)
323 		ip_set_nfnl_put(par->net, info->add_set.index);
324 	if (info->del_set.index != IPSET_INVALID_ID)
325 		ip_set_nfnl_put(par->net, info->del_set.index);
326 }
327 
328 /* Revision 1 target */
329 
330 static unsigned int
331 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
332 {
333 	const struct xt_set_info_target_v1 *info = par->targinfo;
334 
335 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
336 		info->add_set.flags, 0, UINT_MAX);
337 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
338 		info->del_set.flags, 0, UINT_MAX);
339 
340 	if (info->add_set.index != IPSET_INVALID_ID)
341 		ip_set_add(info->add_set.index, skb, par, &add_opt);
342 	if (info->del_set.index != IPSET_INVALID_ID)
343 		ip_set_del(info->del_set.index, skb, par, &del_opt);
344 
345 	return XT_CONTINUE;
346 }
347 
348 static int
349 set_target_v1_checkentry(const struct xt_tgchk_param *par)
350 {
351 	const struct xt_set_info_target_v1 *info = par->targinfo;
352 	ip_set_id_t index;
353 
354 	if (info->add_set.index != IPSET_INVALID_ID) {
355 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
356 		if (index == IPSET_INVALID_ID) {
357 			pr_warn("Cannot find add_set index %u as target\n",
358 				info->add_set.index);
359 			return -ENOENT;
360 		}
361 	}
362 
363 	if (info->del_set.index != IPSET_INVALID_ID) {
364 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
365 		if (index == IPSET_INVALID_ID) {
366 			pr_warn("Cannot find del_set index %u as target\n",
367 				info->del_set.index);
368 			if (info->add_set.index != IPSET_INVALID_ID)
369 				ip_set_nfnl_put(par->net, info->add_set.index);
370 			return -ENOENT;
371 		}
372 	}
373 	if (info->add_set.dim > IPSET_DIM_MAX ||
374 	    info->del_set.dim > IPSET_DIM_MAX) {
375 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
376 		if (info->add_set.index != IPSET_INVALID_ID)
377 			ip_set_nfnl_put(par->net, info->add_set.index);
378 		if (info->del_set.index != IPSET_INVALID_ID)
379 			ip_set_nfnl_put(par->net, info->del_set.index);
380 		return -ERANGE;
381 	}
382 
383 	return 0;
384 }
385 
386 static void
387 set_target_v1_destroy(const struct xt_tgdtor_param *par)
388 {
389 	const struct xt_set_info_target_v1 *info = par->targinfo;
390 
391 	if (info->add_set.index != IPSET_INVALID_ID)
392 		ip_set_nfnl_put(par->net, info->add_set.index);
393 	if (info->del_set.index != IPSET_INVALID_ID)
394 		ip_set_nfnl_put(par->net, info->del_set.index);
395 }
396 
397 /* Revision 2 target */
398 
399 static unsigned int
400 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
401 {
402 	const struct xt_set_info_target_v2 *info = par->targinfo;
403 
404 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
405 		info->add_set.flags, info->flags, info->timeout);
406 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
407 		info->del_set.flags, 0, UINT_MAX);
408 
409 	/* Normalize to fit into jiffies */
410 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
411 	    add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
412 		add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
413 	if (info->add_set.index != IPSET_INVALID_ID)
414 		ip_set_add(info->add_set.index, skb, par, &add_opt);
415 	if (info->del_set.index != IPSET_INVALID_ID)
416 		ip_set_del(info->del_set.index, skb, par, &del_opt);
417 
418 	return XT_CONTINUE;
419 }
420 
421 #define set_target_v2_checkentry	set_target_v1_checkentry
422 #define set_target_v2_destroy		set_target_v1_destroy
423 
424 /* Revision 3 target */
425 
426 #define MOPT(opt, member)	((opt).ext.skbinfo.member)
427 
428 static unsigned int
429 set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
430 {
431 	const struct xt_set_info_target_v3 *info = par->targinfo;
432 	int ret;
433 
434 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
435 		info->add_set.flags, info->flags, info->timeout);
436 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
437 		info->del_set.flags, 0, UINT_MAX);
438 	ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
439 		info->map_set.flags, 0, UINT_MAX);
440 
441 	/* Normalize to fit into jiffies */
442 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
443 	    add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
444 		add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
445 	if (info->add_set.index != IPSET_INVALID_ID)
446 		ip_set_add(info->add_set.index, skb, par, &add_opt);
447 	if (info->del_set.index != IPSET_INVALID_ID)
448 		ip_set_del(info->del_set.index, skb, par, &del_opt);
449 	if (info->map_set.index != IPSET_INVALID_ID) {
450 		map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
451 						   IPSET_FLAG_MAP_SKBPRIO |
452 						   IPSET_FLAG_MAP_SKBQUEUE);
453 		ret = match_set(info->map_set.index, skb, par, &map_opt,
454 				info->map_set.flags & IPSET_INV_MATCH);
455 		if (!ret)
456 			return XT_CONTINUE;
457 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
458 			skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
459 				    ^ MOPT(map_opt, skbmark);
460 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
461 			skb->priority = MOPT(map_opt, skbprio);
462 		if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
463 		    skb->dev &&
464 		    skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
465 			skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
466 	}
467 	return XT_CONTINUE;
468 }
469 
470 static int
471 set_target_v3_checkentry(const struct xt_tgchk_param *par)
472 {
473 	const struct xt_set_info_target_v3 *info = par->targinfo;
474 	ip_set_id_t index;
475 
476 	if (info->add_set.index != IPSET_INVALID_ID) {
477 		index = ip_set_nfnl_get_byindex(par->net,
478 						info->add_set.index);
479 		if (index == IPSET_INVALID_ID) {
480 			pr_warn("Cannot find add_set index %u as target\n",
481 				info->add_set.index);
482 			return -ENOENT;
483 		}
484 	}
485 
486 	if (info->del_set.index != IPSET_INVALID_ID) {
487 		index = ip_set_nfnl_get_byindex(par->net,
488 						info->del_set.index);
489 		if (index == IPSET_INVALID_ID) {
490 			pr_warn("Cannot find del_set index %u as target\n",
491 				info->del_set.index);
492 			if (info->add_set.index != IPSET_INVALID_ID)
493 				ip_set_nfnl_put(par->net,
494 						info->add_set.index);
495 			return -ENOENT;
496 		}
497 	}
498 
499 	if (info->map_set.index != IPSET_INVALID_ID) {
500 		if (strncmp(par->table, "mangle", 7)) {
501 			pr_warn("--map-set only usable from mangle table\n");
502 			return -EINVAL;
503 		}
504 		if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
505 		     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
506 		     !(par->hook_mask & (1 << NF_INET_FORWARD |
507 					 1 << NF_INET_LOCAL_OUT |
508 					 1 << NF_INET_POST_ROUTING))) {
509 			pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
510 			return -EINVAL;
511 		}
512 		index = ip_set_nfnl_get_byindex(par->net,
513 						info->map_set.index);
514 		if (index == IPSET_INVALID_ID) {
515 			pr_warn("Cannot find map_set index %u as target\n",
516 				info->map_set.index);
517 			if (info->add_set.index != IPSET_INVALID_ID)
518 				ip_set_nfnl_put(par->net,
519 						info->add_set.index);
520 			if (info->del_set.index != IPSET_INVALID_ID)
521 				ip_set_nfnl_put(par->net,
522 						info->del_set.index);
523 			return -ENOENT;
524 		}
525 	}
526 
527 	if (info->add_set.dim > IPSET_DIM_MAX ||
528 	    info->del_set.dim > IPSET_DIM_MAX ||
529 	    info->map_set.dim > IPSET_DIM_MAX) {
530 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
531 		if (info->add_set.index != IPSET_INVALID_ID)
532 			ip_set_nfnl_put(par->net, info->add_set.index);
533 		if (info->del_set.index != IPSET_INVALID_ID)
534 			ip_set_nfnl_put(par->net, info->del_set.index);
535 		if (info->map_set.index != IPSET_INVALID_ID)
536 			ip_set_nfnl_put(par->net, info->map_set.index);
537 		return -ERANGE;
538 	}
539 
540 	return 0;
541 }
542 
543 static void
544 set_target_v3_destroy(const struct xt_tgdtor_param *par)
545 {
546 	const struct xt_set_info_target_v3 *info = par->targinfo;
547 
548 	if (info->add_set.index != IPSET_INVALID_ID)
549 		ip_set_nfnl_put(par->net, info->add_set.index);
550 	if (info->del_set.index != IPSET_INVALID_ID)
551 		ip_set_nfnl_put(par->net, info->del_set.index);
552 	if (info->map_set.index != IPSET_INVALID_ID)
553 		ip_set_nfnl_put(par->net, info->map_set.index);
554 }
555 
556 static struct xt_match set_matches[] __read_mostly = {
557 	{
558 		.name		= "set",
559 		.family		= NFPROTO_IPV4,
560 		.revision	= 0,
561 		.match		= set_match_v0,
562 		.matchsize	= sizeof(struct xt_set_info_match_v0),
563 		.checkentry	= set_match_v0_checkentry,
564 		.destroy	= set_match_v0_destroy,
565 		.me		= THIS_MODULE
566 	},
567 	{
568 		.name		= "set",
569 		.family		= NFPROTO_IPV4,
570 		.revision	= 1,
571 		.match		= set_match_v1,
572 		.matchsize	= sizeof(struct xt_set_info_match_v1),
573 		.checkentry	= set_match_v1_checkentry,
574 		.destroy	= set_match_v1_destroy,
575 		.me		= THIS_MODULE
576 	},
577 	{
578 		.name		= "set",
579 		.family		= NFPROTO_IPV6,
580 		.revision	= 1,
581 		.match		= set_match_v1,
582 		.matchsize	= sizeof(struct xt_set_info_match_v1),
583 		.checkentry	= set_match_v1_checkentry,
584 		.destroy	= set_match_v1_destroy,
585 		.me		= THIS_MODULE
586 	},
587 	/* --return-nomatch flag support */
588 	{
589 		.name		= "set",
590 		.family		= NFPROTO_IPV4,
591 		.revision	= 2,
592 		.match		= set_match_v1,
593 		.matchsize	= sizeof(struct xt_set_info_match_v1),
594 		.checkentry	= set_match_v1_checkentry,
595 		.destroy	= set_match_v1_destroy,
596 		.me		= THIS_MODULE
597 	},
598 	{
599 		.name		= "set",
600 		.family		= NFPROTO_IPV6,
601 		.revision	= 2,
602 		.match		= set_match_v1,
603 		.matchsize	= sizeof(struct xt_set_info_match_v1),
604 		.checkentry	= set_match_v1_checkentry,
605 		.destroy	= set_match_v1_destroy,
606 		.me		= THIS_MODULE
607 	},
608 	/* counters support: update, match */
609 	{
610 		.name		= "set",
611 		.family		= NFPROTO_IPV4,
612 		.revision	= 3,
613 		.match		= set_match_v3,
614 		.matchsize	= sizeof(struct xt_set_info_match_v3),
615 		.checkentry	= set_match_v3_checkentry,
616 		.destroy	= set_match_v3_destroy,
617 		.me		= THIS_MODULE
618 	},
619 	{
620 		.name		= "set",
621 		.family		= NFPROTO_IPV6,
622 		.revision	= 3,
623 		.match		= set_match_v3,
624 		.matchsize	= sizeof(struct xt_set_info_match_v3),
625 		.checkentry	= set_match_v3_checkentry,
626 		.destroy	= set_match_v3_destroy,
627 		.me		= THIS_MODULE
628 	},
629 	/* new revision for counters support: update, match */
630 	{
631 		.name		= "set",
632 		.family		= NFPROTO_IPV4,
633 		.revision	= 4,
634 		.match		= set_match_v4,
635 		.matchsize	= sizeof(struct xt_set_info_match_v4),
636 		.checkentry	= set_match_v4_checkentry,
637 		.destroy	= set_match_v4_destroy,
638 		.me		= THIS_MODULE
639 	},
640 	{
641 		.name		= "set",
642 		.family		= NFPROTO_IPV6,
643 		.revision	= 4,
644 		.match		= set_match_v4,
645 		.matchsize	= sizeof(struct xt_set_info_match_v4),
646 		.checkentry	= set_match_v4_checkentry,
647 		.destroy	= set_match_v4_destroy,
648 		.me		= THIS_MODULE
649 	},
650 };
651 
652 static struct xt_target set_targets[] __read_mostly = {
653 	{
654 		.name		= "SET",
655 		.revision	= 0,
656 		.family		= NFPROTO_IPV4,
657 		.target		= set_target_v0,
658 		.targetsize	= sizeof(struct xt_set_info_target_v0),
659 		.checkentry	= set_target_v0_checkentry,
660 		.destroy	= set_target_v0_destroy,
661 		.me		= THIS_MODULE
662 	},
663 	{
664 		.name		= "SET",
665 		.revision	= 1,
666 		.family		= NFPROTO_IPV4,
667 		.target		= set_target_v1,
668 		.targetsize	= sizeof(struct xt_set_info_target_v1),
669 		.checkentry	= set_target_v1_checkentry,
670 		.destroy	= set_target_v1_destroy,
671 		.me		= THIS_MODULE
672 	},
673 	{
674 		.name		= "SET",
675 		.revision	= 1,
676 		.family		= NFPROTO_IPV6,
677 		.target		= set_target_v1,
678 		.targetsize	= sizeof(struct xt_set_info_target_v1),
679 		.checkentry	= set_target_v1_checkentry,
680 		.destroy	= set_target_v1_destroy,
681 		.me		= THIS_MODULE
682 	},
683 	/* --timeout and --exist flags support */
684 	{
685 		.name		= "SET",
686 		.revision	= 2,
687 		.family		= NFPROTO_IPV4,
688 		.target		= set_target_v2,
689 		.targetsize	= sizeof(struct xt_set_info_target_v2),
690 		.checkentry	= set_target_v2_checkentry,
691 		.destroy	= set_target_v2_destroy,
692 		.me		= THIS_MODULE
693 	},
694 	{
695 		.name		= "SET",
696 		.revision	= 2,
697 		.family		= NFPROTO_IPV6,
698 		.target		= set_target_v2,
699 		.targetsize	= sizeof(struct xt_set_info_target_v2),
700 		.checkentry	= set_target_v2_checkentry,
701 		.destroy	= set_target_v2_destroy,
702 		.me		= THIS_MODULE
703 	},
704 	/* --map-set support */
705 	{
706 		.name		= "SET",
707 		.revision	= 3,
708 		.family		= NFPROTO_IPV4,
709 		.target		= set_target_v3,
710 		.targetsize	= sizeof(struct xt_set_info_target_v3),
711 		.checkentry	= set_target_v3_checkentry,
712 		.destroy	= set_target_v3_destroy,
713 		.me		= THIS_MODULE
714 	},
715 	{
716 		.name		= "SET",
717 		.revision	= 3,
718 		.family		= NFPROTO_IPV6,
719 		.target		= set_target_v3,
720 		.targetsize	= sizeof(struct xt_set_info_target_v3),
721 		.checkentry	= set_target_v3_checkentry,
722 		.destroy	= set_target_v3_destroy,
723 		.me		= THIS_MODULE
724 	},
725 };
726 
727 static int __init xt_set_init(void)
728 {
729 	int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
730 
731 	if (!ret) {
732 		ret = xt_register_targets(set_targets,
733 					  ARRAY_SIZE(set_targets));
734 		if (ret)
735 			xt_unregister_matches(set_matches,
736 					      ARRAY_SIZE(set_matches));
737 	}
738 	return ret;
739 }
740 
741 static void __exit xt_set_fini(void)
742 {
743 	xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
744 	xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
745 }
746 
747 module_init(xt_set_init);
748 module_exit(xt_set_fini);
749