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