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