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