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