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-2010 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/* Shared library add-on to iptables to add IP set matching. */
12#include <stdbool.h>
13#include <stdio.h>
14#include <netdb.h>
15#include <string.h>
16#include <stdlib.h>
17#include <getopt.h>
18#include <ctype.h>
19#include <errno.h>
20
21#include <xtables.h>
22#include <linux/netfilter/xt_set.h>
23#include "libxt_set.h"
24
25/* Revision 0 */
26
27static void
28set_help_v0(void)
29{
30	printf("set match options:\n"
31	       " [!] --match-set name flags\n"
32	       "		 'name' is the set name from to match,\n"
33	       "		 'flags' are the comma separated list of\n"
34	       "		 'src' and 'dst' specifications.\n");
35}
36
37static const struct option set_opts_v0[] = {
38	{.name = "match-set", .has_arg = true, .val = '1'},
39	{.name = "set",       .has_arg = true, .val = '2'},
40	XT_GETOPT_TABLEEND,
41};
42
43static void
44set_check_v0(unsigned int flags)
45{
46	if (!flags)
47		xtables_error(PARAMETER_PROBLEM,
48			"You must specify `--match-set' with proper arguments");
49}
50
51static int
52set_parse_v0(int c, char **argv, int invert, unsigned int *flags,
53	     const void *entry, struct xt_entry_match **match)
54{
55	struct xt_set_info_match_v0 *myinfo =
56		(struct xt_set_info_match_v0 *) (*match)->data;
57	struct xt_set_info_v0 *info = &myinfo->match_set;
58
59	switch (c) {
60	case '2':
61		fprintf(stderr,
62			"--set option deprecated, please use --match-set\n");
63	case '1':		/* --match-set <set> <flag>[,<flag> */
64		if (info->u.flags[0])
65			xtables_error(PARAMETER_PROBLEM,
66				      "--match-set can be specified only once");
67		if (invert)
68			info->u.flags[0] |= IPSET_MATCH_INV;
69
70		if (!argv[optind]
71		    || argv[optind][0] == '-'
72		    || argv[optind][0] == '!')
73			xtables_error(PARAMETER_PROBLEM,
74				      "--match-set requires two args.");
75
76		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
77			xtables_error(PARAMETER_PROBLEM,
78				      "setname `%s' too long, max %d characters.",
79				      optarg, IPSET_MAXNAMELEN - 1);
80
81		get_set_byname(optarg, (struct xt_set_info *)info);
82		parse_dirs_v0(argv[optind], info);
83		DEBUGP("parse: set index %u\n", info->index);
84		optind++;
85
86		*flags = 1;
87		break;
88	}
89
90	return 1;
91}
92
93static void
94print_match_v0(const char *prefix, const struct xt_set_info_v0 *info)
95{
96	int i;
97	char setname[IPSET_MAXNAMELEN];
98
99	get_set_byid(setname, info->index);
100	printf("%s %s %s",
101	       (info->u.flags[0] & IPSET_MATCH_INV) ? " !" : "",
102	       prefix,
103	       setname);
104	for (i = 0; i < IPSET_DIM_MAX; i++) {
105		if (!info->u.flags[i])
106			break;
107		printf("%s%s",
108		       i == 0 ? " " : ",",
109		       info->u.flags[i] & IPSET_SRC ? "src" : "dst");
110	}
111}
112
113/* Prints out the matchinfo. */
114static void
115set_print_v0(const void *ip, const struct xt_entry_match *match, int numeric)
116{
117	const struct xt_set_info_match_v0 *info = (const void *)match->data;
118
119	print_match_v0("match-set", &info->match_set);
120}
121
122static void
123set_save_v0(const void *ip, const struct xt_entry_match *match)
124{
125	const struct xt_set_info_match_v0 *info = (const void *)match->data;
126
127	print_match_v0("--match-set", &info->match_set);
128}
129
130/* Revision 1 */
131static int
132set_parse_v1(int c, char **argv, int invert, unsigned int *flags,
133	     const void *entry, struct xt_entry_match **match)
134{
135	struct xt_set_info_match_v1 *myinfo =
136		(struct xt_set_info_match_v1 *) (*match)->data;
137	struct xt_set_info *info = &myinfo->match_set;
138
139	switch (c) {
140	case '2':
141		fprintf(stderr,
142			"--set option deprecated, please use --match-set\n");
143	case '1':		/* --match-set <set> <flag>[,<flag> */
144		if (info->dim)
145			xtables_error(PARAMETER_PROBLEM,
146				      "--match-set can be specified only once");
147		if (invert)
148			info->flags |= IPSET_INV_MATCH;
149
150		if (!argv[optind]
151		    || argv[optind][0] == '-'
152		    || argv[optind][0] == '!')
153			xtables_error(PARAMETER_PROBLEM,
154				      "--match-set requires two args.");
155
156		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
157			xtables_error(PARAMETER_PROBLEM,
158				      "setname `%s' too long, max %d characters.",
159				      optarg, IPSET_MAXNAMELEN - 1);
160
161		get_set_byname(optarg, info);
162		parse_dirs(argv[optind], info);
163		DEBUGP("parse: set index %u\n", info->index);
164		optind++;
165
166		*flags = 1;
167		break;
168	}
169
170	return 1;
171}
172
173static void
174print_match(const char *prefix, const struct xt_set_info *info)
175{
176	int i;
177	char setname[IPSET_MAXNAMELEN];
178
179	get_set_byid(setname, info->index);
180	printf("%s %s %s",
181	       (info->flags & IPSET_INV_MATCH) ? " !" : "",
182	       prefix,
183	       setname);
184	for (i = 1; i <= info->dim; i++) {
185		printf("%s%s",
186		       i == 1 ? " " : ",",
187		       info->flags & (1 << i) ? "src" : "dst");
188	}
189}
190
191/* Prints out the matchinfo. */
192static void
193set_print_v1(const void *ip, const struct xt_entry_match *match, int numeric)
194{
195	const struct xt_set_info_match_v1 *info = (const void *)match->data;
196
197	print_match("match-set", &info->match_set);
198}
199
200static void
201set_save_v1(const void *ip, const struct xt_entry_match *match)
202{
203	const struct xt_set_info_match_v1 *info = (const void *)match->data;
204
205	print_match("--match-set", &info->match_set);
206}
207
208/* Revision 2 */
209static void
210set_help_v2(void)
211{
212	printf("set match options:\n"
213	       " [!] --match-set name flags [--return-nomatch]\n"
214	       "		 'name' is the set name from to match,\n"
215	       "		 'flags' are the comma separated list of\n"
216	       "		 'src' and 'dst' specifications.\n");
217}
218
219static const struct option set_opts_v2[] = {
220	{.name = "match-set",		.has_arg = true,	.val = '1'},
221	{.name = "set",			.has_arg = true,	.val = '2'},
222	{.name = "return-nomatch",	.has_arg = false,	.val = '3'},
223	XT_GETOPT_TABLEEND,
224};
225
226static int
227set_parse_v2(int c, char **argv, int invert, unsigned int *flags,
228	     const void *entry, struct xt_entry_match **match)
229{
230	struct xt_set_info_match_v1 *myinfo =
231		(struct xt_set_info_match_v1 *) (*match)->data;
232	struct xt_set_info *info = &myinfo->match_set;
233
234	switch (c) {
235	case '3':
236		info->flags |= IPSET_RETURN_NOMATCH;
237		break;
238	case '2':
239		fprintf(stderr,
240			"--set option deprecated, please use --match-set\n");
241	case '1':		/* --match-set <set> <flag>[,<flag> */
242		if (info->dim)
243			xtables_error(PARAMETER_PROBLEM,
244				      "--match-set can be specified only once");
245		if (invert)
246			info->flags |= IPSET_INV_MATCH;
247
248		if (!argv[optind]
249		    || argv[optind][0] == '-'
250		    || argv[optind][0] == '!')
251			xtables_error(PARAMETER_PROBLEM,
252				      "--match-set requires two args.");
253
254		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
255			xtables_error(PARAMETER_PROBLEM,
256				      "setname `%s' too long, max %d characters.",
257				      optarg, IPSET_MAXNAMELEN - 1);
258
259		get_set_byname(optarg, info);
260		parse_dirs(argv[optind], info);
261		DEBUGP("parse: set index %u\n", info->index);
262		optind++;
263
264		*flags = 1;
265		break;
266	}
267
268	return 1;
269}
270
271/* Prints out the matchinfo. */
272static void
273set_print_v2(const void *ip, const struct xt_entry_match *match, int numeric)
274{
275	const struct xt_set_info_match_v1 *info = (const void *)match->data;
276
277	print_match("match-set", &info->match_set);
278	if (info->match_set.flags & IPSET_RETURN_NOMATCH)
279		printf(" return-nomatch");
280}
281
282static void
283set_save_v2(const void *ip, const struct xt_entry_match *match)
284{
285	const struct xt_set_info_match_v1 *info = (const void *)match->data;
286
287	print_match("--match-set", &info->match_set);
288	if (info->match_set.flags & IPSET_RETURN_NOMATCH)
289		printf(" --return-nomatch");
290}
291
292/* Revision 3 */
293static void
294set_help_v3(void)
295{
296	printf("set match options:\n"
297	       " [!] --match-set name flags [--return-nomatch]\n"
298	       "   [! --update-counters] [! --update-subcounters]\n"
299	       "   [[!] --packets-eq value | --packets-lt value | --packets-gt value\n"
300	       "   [[!] --bytes-eq value | --bytes-lt value | --bytes-gt value\n"
301	       "		 'name' is the set name from to match,\n"
302	       "		 'flags' are the comma separated list of\n"
303	       "		 'src' and 'dst' specifications.\n");
304}
305
306static const struct option set_opts_v3[] = {
307	{.name = "match-set",		.has_arg = true,	.val = '1'},
308	{.name = "set",			.has_arg = true,	.val = '2'},
309	{.name = "return-nomatch",	.has_arg = false,	.val = '3'},
310	{.name = "update-counters",	.has_arg = false,	.val = '4'},
311	{.name = "packets-eq",		.has_arg = true,	.val = '5'},
312	{.name = "packets-lt",		.has_arg = true,	.val = '6'},
313	{.name = "packets-gt",		.has_arg = true,	.val = '7'},
314	{.name = "bytes-eq",		.has_arg = true,	.val = '8'},
315	{.name = "bytes-lt",		.has_arg = true,	.val = '9'},
316	{.name = "bytes-gt",		.has_arg = true,	.val = '0'},
317	{.name = "update-subcounters",	.has_arg = false,	.val = 'a'},
318	XT_GETOPT_TABLEEND,
319};
320
321static uint64_t
322parse_counter(const char *opt)
323{
324	uintmax_t value;
325
326	if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX))
327		xtables_error(PARAMETER_PROBLEM,
328			      "Cannot parse %s as a counter value\n",
329			      opt);
330	return (uint64_t)value;
331}
332
333static int
334set_parse_v3(int c, char **argv, int invert, unsigned int *flags,
335	     const void *entry, struct xt_entry_match **match)
336{
337	struct xt_set_info_match_v3 *info =
338		(struct xt_set_info_match_v3 *) (*match)->data;
339
340	switch (c) {
341	case 'a':
342		if (invert)
343			info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE;
344		break;
345	case '0':
346		if (info->bytes.op != IPSET_COUNTER_NONE)
347			xtables_error(PARAMETER_PROBLEM,
348				      "only one of the --bytes-[eq|lt|gt]"
349				      " is allowed\n");
350		if (invert)
351			xtables_error(PARAMETER_PROBLEM,
352				      "--bytes-gt option cannot be inverted\n");
353		info->bytes.op = IPSET_COUNTER_GT;
354		info->bytes.value = parse_counter(optarg);
355		break;
356	case '9':
357		if (info->bytes.op != IPSET_COUNTER_NONE)
358			xtables_error(PARAMETER_PROBLEM,
359				      "only one of the --bytes-[eq|lt|gt]"
360				      " is allowed\n");
361		if (invert)
362			xtables_error(PARAMETER_PROBLEM,
363				      "--bytes-lt option cannot be inverted\n");
364		info->bytes.op = IPSET_COUNTER_LT;
365		info->bytes.value = parse_counter(optarg);
366		break;
367	case '8':
368		if (info->bytes.op != IPSET_COUNTER_NONE)
369			xtables_error(PARAMETER_PROBLEM,
370				      "only one of the --bytes-[eq|lt|gt]"
371				      " is allowed\n");
372		info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
373		info->bytes.value = parse_counter(optarg);
374		break;
375	case '7':
376		if (info->packets.op != IPSET_COUNTER_NONE)
377			xtables_error(PARAMETER_PROBLEM,
378				      "only one of the --packets-[eq|lt|gt]"
379				      " is allowed\n");
380		if (invert)
381			xtables_error(PARAMETER_PROBLEM,
382				      "--packets-gt option cannot be inverted\n");
383		info->packets.op = IPSET_COUNTER_GT;
384		info->packets.value = parse_counter(optarg);
385		break;
386	case '6':
387		if (info->packets.op != IPSET_COUNTER_NONE)
388			xtables_error(PARAMETER_PROBLEM,
389				      "only one of the --packets-[eq|lt|gt]"
390				      " is allowed\n");
391		if (invert)
392			xtables_error(PARAMETER_PROBLEM,
393				      "--packets-lt option cannot be inverted\n");
394		info->packets.op = IPSET_COUNTER_LT;
395		info->packets.value = parse_counter(optarg);
396		break;
397	case '5':
398		if (info->packets.op != IPSET_COUNTER_NONE)
399			xtables_error(PARAMETER_PROBLEM,
400				      "only one of the --packets-[eq|lt|gt]"
401				      " is allowed\n");
402		info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
403		info->packets.value = parse_counter(optarg);
404		break;
405	case '4':
406		if (invert)
407			info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE;
408		break;
409	case '3':
410		if (invert)
411			xtables_error(PARAMETER_PROBLEM,
412				      "--return-nomatch flag cannot be inverted\n");
413		info->flags |= IPSET_FLAG_RETURN_NOMATCH;
414		break;
415	case '2':
416		fprintf(stderr,
417			"--set option deprecated, please use --match-set\n");
418	case '1':		/* --match-set <set> <flag>[,<flag> */
419		if (info->match_set.dim)
420			xtables_error(PARAMETER_PROBLEM,
421				      "--match-set can be specified only once");
422		if (invert)
423			info->match_set.flags |= IPSET_INV_MATCH;
424
425		if (!argv[optind]
426		    || argv[optind][0] == '-'
427		    || argv[optind][0] == '!')
428			xtables_error(PARAMETER_PROBLEM,
429				      "--match-set requires two args.");
430
431		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
432			xtables_error(PARAMETER_PROBLEM,
433				      "setname `%s' too long, max %d characters.",
434				      optarg, IPSET_MAXNAMELEN - 1);
435
436		get_set_byname(optarg, &info->match_set);
437		parse_dirs(argv[optind], &info->match_set);
438		DEBUGP("parse: set index %u\n", info->match_set.index);
439		optind++;
440
441		*flags = 1;
442		break;
443	}
444
445	return 1;
446}
447
448static void
449set_printv3_counter(const struct ip_set_counter_match0 *c, const char *name,
450		    const char *sep)
451{
452	switch (c->op) {
453	case IPSET_COUNTER_EQ:
454		printf(" %s%s-eq %llu", sep, name, c->value);
455		break;
456	case IPSET_COUNTER_NE:
457		printf(" ! %s%s-eq %llu", sep, name, c->value);
458		break;
459	case IPSET_COUNTER_LT:
460		printf(" %s%s-lt %llu", sep, name, c->value);
461		break;
462	case IPSET_COUNTER_GT:
463		printf(" %s%s-gt %llu", sep, name, c->value);
464		break;
465	}
466}
467
468static void
469set_print_v3_matchinfo(const struct xt_set_info_match_v3 *info,
470		       const char *opt, const char *sep)
471{
472	print_match(opt, &info->match_set);
473	if (info->flags & IPSET_FLAG_RETURN_NOMATCH)
474		printf(" %sreturn-nomatch", sep);
475	if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE))
476		printf(" ! %supdate-counters", sep);
477	if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE))
478		printf(" ! %supdate-subcounters", sep);
479	set_printv3_counter(&info->packets, "packets", sep);
480	set_printv3_counter(&info->bytes, "bytes", sep);
481}
482
483/* Prints out the matchinfo. */
484static void
485set_print_v3(const void *ip, const struct xt_entry_match *match, int numeric)
486{
487	const struct xt_set_info_match_v3 *info = (const void *)match->data;
488
489	set_print_v3_matchinfo(info, "match-set", "");
490}
491
492static void
493set_save_v3(const void *ip, const struct xt_entry_match *match)
494{
495	const struct xt_set_info_match_v3 *info = (const void *)match->data;
496
497	set_print_v3_matchinfo(info, "--match-set", "--");
498}
499
500/* Revision 4 */
501static int
502set_parse_v4(int c, char **argv, int invert, unsigned int *flags,
503	     const void *entry, struct xt_entry_match **match)
504{
505	struct xt_set_info_match_v4 *info =
506		(struct xt_set_info_match_v4 *) (*match)->data;
507
508	switch (c) {
509	case 'a':
510		if (invert)
511			info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE;
512		break;
513	case '0':
514		if (info->bytes.op != IPSET_COUNTER_NONE)
515			xtables_error(PARAMETER_PROBLEM,
516				      "only one of the --bytes-[eq|lt|gt]"
517				      " is allowed\n");
518		if (invert)
519			xtables_error(PARAMETER_PROBLEM,
520				      "--bytes-gt option cannot be inverted\n");
521		info->bytes.op = IPSET_COUNTER_GT;
522		info->bytes.value = parse_counter(optarg);
523		break;
524	case '9':
525		if (info->bytes.op != IPSET_COUNTER_NONE)
526			xtables_error(PARAMETER_PROBLEM,
527				      "only one of the --bytes-[eq|lt|gt]"
528				      " is allowed\n");
529		if (invert)
530			xtables_error(PARAMETER_PROBLEM,
531				      "--bytes-lt option cannot be inverted\n");
532		info->bytes.op = IPSET_COUNTER_LT;
533		info->bytes.value = parse_counter(optarg);
534		break;
535	case '8':
536		if (info->bytes.op != IPSET_COUNTER_NONE)
537			xtables_error(PARAMETER_PROBLEM,
538				      "only one of the --bytes-[eq|lt|gt]"
539				      " is allowed\n");
540		info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
541		info->bytes.value = parse_counter(optarg);
542		break;
543	case '7':
544		if (info->packets.op != IPSET_COUNTER_NONE)
545			xtables_error(PARAMETER_PROBLEM,
546				      "only one of the --packets-[eq|lt|gt]"
547				      " is allowed\n");
548		if (invert)
549			xtables_error(PARAMETER_PROBLEM,
550				      "--packets-gt option cannot be inverted\n");
551		info->packets.op = IPSET_COUNTER_GT;
552		info->packets.value = parse_counter(optarg);
553		break;
554	case '6':
555		if (info->packets.op != IPSET_COUNTER_NONE)
556			xtables_error(PARAMETER_PROBLEM,
557				      "only one of the --packets-[eq|lt|gt]"
558				      " is allowed\n");
559		if (invert)
560			xtables_error(PARAMETER_PROBLEM,
561				      "--packets-lt option cannot be inverted\n");
562		info->packets.op = IPSET_COUNTER_LT;
563		info->packets.value = parse_counter(optarg);
564		break;
565	case '5':
566		if (info->packets.op != IPSET_COUNTER_NONE)
567			xtables_error(PARAMETER_PROBLEM,
568				      "only one of the --packets-[eq|lt|gt]"
569				      " is allowed\n");
570		info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ;
571		info->packets.value = parse_counter(optarg);
572		break;
573	case '4':
574		if (invert)
575			info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE;
576		break;
577	case '3':
578		if (invert)
579			xtables_error(PARAMETER_PROBLEM,
580				      "--return-nomatch flag cannot be inverted\n");
581		info->flags |= IPSET_FLAG_RETURN_NOMATCH;
582		break;
583	case '2':
584		fprintf(stderr,
585			"--set option deprecated, please use --match-set\n");
586	case '1':		/* --match-set <set> <flag>[,<flag> */
587		if (info->match_set.dim)
588			xtables_error(PARAMETER_PROBLEM,
589				      "--match-set can be specified only once");
590		if (invert)
591			info->match_set.flags |= IPSET_INV_MATCH;
592
593		if (!argv[optind]
594		    || argv[optind][0] == '-'
595		    || argv[optind][0] == '!')
596			xtables_error(PARAMETER_PROBLEM,
597				      "--match-set requires two args.");
598
599		if (strlen(optarg) > IPSET_MAXNAMELEN - 1)
600			xtables_error(PARAMETER_PROBLEM,
601				      "setname `%s' too long, max %d characters.",
602				      optarg, IPSET_MAXNAMELEN - 1);
603
604		get_set_byname(optarg, &info->match_set);
605		parse_dirs(argv[optind], &info->match_set);
606		DEBUGP("parse: set index %u\n", info->match_set.index);
607		optind++;
608
609		*flags = 1;
610		break;
611	}
612
613	return 1;
614}
615
616static void
617set_printv4_counter(const struct ip_set_counter_match *c, const char *name,
618		    const char *sep)
619{
620	switch (c->op) {
621	case IPSET_COUNTER_EQ:
622		printf(" %s%s-eq %llu", sep, name, c->value);
623		break;
624	case IPSET_COUNTER_NE:
625		printf(" ! %s%s-eq %llu", sep, name, c->value);
626		break;
627	case IPSET_COUNTER_LT:
628		printf(" %s%s-lt %llu", sep, name, c->value);
629		break;
630	case IPSET_COUNTER_GT:
631		printf(" %s%s-gt %llu", sep, name, c->value);
632		break;
633	}
634}
635
636static void
637set_print_v4_matchinfo(const struct xt_set_info_match_v4 *info,
638		       const char *opt, const char *sep)
639{
640	print_match(opt, &info->match_set);
641	if (info->flags & IPSET_FLAG_RETURN_NOMATCH)
642		printf(" %sreturn-nomatch", sep);
643	if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE))
644		printf(" ! %supdate-counters", sep);
645	if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE))
646		printf(" ! %supdate-subcounters", sep);
647	set_printv4_counter(&info->packets, "packets", sep);
648	set_printv4_counter(&info->bytes, "bytes", sep);
649}
650
651/* Prints out the matchinfo. */
652static void
653set_print_v4(const void *ip, const struct xt_entry_match *match, int numeric)
654{
655	const struct xt_set_info_match_v4 *info = (const void *)match->data;
656
657	set_print_v4_matchinfo(info, "match-set", "");
658}
659
660static void
661set_save_v4(const void *ip, const struct xt_entry_match *match)
662{
663	const struct xt_set_info_match_v4 *info = (const void *)match->data;
664
665	set_print_v4_matchinfo(info, "--match-set", "--");
666}
667
668static struct xtables_match set_mt_reg[] = {
669	{
670		.name		= "set",
671		.revision	= 0,
672		.version	= XTABLES_VERSION,
673		.family		= NFPROTO_IPV4,
674		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
675		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v0)),
676		.help		= set_help_v0,
677		.parse		= set_parse_v0,
678		.final_check	= set_check_v0,
679		.print		= set_print_v0,
680		.save		= set_save_v0,
681		.extra_opts	= set_opts_v0,
682	},
683	{
684		.name		= "set",
685		.revision	= 1,
686		.version	= XTABLES_VERSION,
687		.family		= NFPROTO_UNSPEC,
688		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
689		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
690		.help		= set_help_v0,
691		.parse		= set_parse_v1,
692		.final_check	= set_check_v0,
693		.print		= set_print_v1,
694		.save		= set_save_v1,
695		.extra_opts	= set_opts_v0,
696	},
697	{
698		.name		= "set",
699		.revision	= 2,
700		.version	= XTABLES_VERSION,
701		.family		= NFPROTO_UNSPEC,
702		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
703		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v1)),
704		.help		= set_help_v2,
705		.parse		= set_parse_v2,
706		.final_check	= set_check_v0,
707		.print		= set_print_v2,
708		.save		= set_save_v2,
709		.extra_opts	= set_opts_v2,
710	},
711	{
712		.name		= "set",
713		.revision	= 3,
714		.version	= XTABLES_VERSION,
715		.family		= NFPROTO_UNSPEC,
716		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v3)),
717		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v3)),
718		.help		= set_help_v3,
719		.parse		= set_parse_v3,
720		.final_check	= set_check_v0,
721		.print		= set_print_v3,
722		.save		= set_save_v3,
723		.extra_opts	= set_opts_v3,
724	},
725	{
726		.name		= "set",
727		.revision	= 4,
728		.version	= XTABLES_VERSION,
729		.family		= NFPROTO_UNSPEC,
730		.size		= XT_ALIGN(sizeof(struct xt_set_info_match_v4)),
731		.userspacesize	= XT_ALIGN(sizeof(struct xt_set_info_match_v4)),
732		.help		= set_help_v3,
733		.parse		= set_parse_v4,
734		.final_check	= set_check_v0,
735		.print		= set_print_v4,
736		.save		= set_save_v4,
737		.extra_opts	= set_opts_v3,
738	},
739};
740
741void _init(void)
742{
743	xtables_register_matches(set_mt_reg, ARRAY_SIZE(set_mt_reg));
744}
745