From 34844da8f53ec80b34ad094f2fca2519a7079ec2 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Wed, 1 May 2013 00:56:35 +0200 Subject: Introduce a new revision for the set match with the counters support The revision add the support of matching the packet/byte counters if the set was defined with the extension. Also, a new flag is introduced to suppress updating the packet/byte counters if required. Signed-off-by: Jozsef Kadlecsik --- extensions/libxt_set.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) (limited to 'extensions/libxt_set.c') diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c index e0111568..2cb9e78a 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -289,6 +289,214 @@ set_save_v2(const void *ip, const struct xt_entry_match *match) printf(" --return-nomatch"); } +/* Revision 3 */ +static void +set_help_v3(void) +{ + printf("set match options:\n" + " [!] --match-set name flags [--return-nomatch]\n" + " [! --update-counters] [! --update-subcounters]\n" + " [[!] --packets-eq value | --packets-lt value | --packets-gt value\n" + " [[!] --bytes-eq value | --bytes-lt value | --bytes-gt value\n" + " 'name' is the set name from to match,\n" + " 'flags' are the comma separated list of\n" + " 'src' and 'dst' specifications.\n"); +} + +static const struct option set_opts_v3[] = { + {.name = "match-set", .has_arg = true, .val = '1'}, + {.name = "set", .has_arg = true, .val = '2'}, + {.name = "return-nomatch", .has_arg = false, .val = '3'}, + {.name = "update-counters", .has_arg = false, .val = '4'}, + {.name = "packets-eq", .has_arg = true, .val = '5'}, + {.name = "packets-lt", .has_arg = true, .val = '6'}, + {.name = "packets-gt", .has_arg = true, .val = '7'}, + {.name = "bytes-eq", .has_arg = true, .val = '8'}, + {.name = "bytes-lt", .has_arg = true, .val = '9'}, + {.name = "bytes-gt", .has_arg = true, .val = '0'}, + {.name = "update-subcounters", .has_arg = false, .val = 'a'}, + XT_GETOPT_TABLEEND, +}; + +static uint64_t +parse_counter(const char *opt) +{ + uintmax_t value; + + if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Cannot parse %s as a counter value\n", + opt); + return (uint64_t)value; +} + +static int +set_parse_v3(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_set_info_match_v3 *info = + (struct xt_set_info_match_v3 *) (*match)->data; + + switch (c) { + case 'a': + if (invert) + info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE; + break; + case '0': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-gt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_GT; + info->bytes.value = parse_counter(optarg); + break; + case '9': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-lt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_LT; + info->bytes.value = parse_counter(optarg); + break; + case '8': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->bytes.value = parse_counter(optarg); + break; + case '7': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-gt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_GT; + info->packets.value = parse_counter(optarg); + break; + case '6': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-lt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_LT; + info->packets.value = parse_counter(optarg); + break; + case '5': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->packets.value = parse_counter(optarg); + break; + case '4': + if (invert) + info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE; + break; + case '3': + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--return-nomatch flag cannot be inverted\n"); + info->flags |= IPSET_FLAG_RETURN_NOMATCH; + break; + case '2': + fprintf(stderr, + "--set option deprecated, please use --match-set\n"); + case '1': /* --match-set [, */ + if (info->match_set.dim) + xtables_error(PARAMETER_PROBLEM, + "--match-set can be specified only once"); + if (invert) + info->match_set.flags |= IPSET_INV_MATCH; + + if (!argv[optind] + || argv[optind][0] == '-' + || argv[optind][0] == '!') + xtables_error(PARAMETER_PROBLEM, + "--match-set requires two args."); + + if (strlen(optarg) > IPSET_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "setname `%s' too long, max %d characters.", + optarg, IPSET_MAXNAMELEN - 1); + + get_set_byname(optarg, &info->match_set); + parse_dirs(argv[optind], &info->match_set); + DEBUGP("parse: set index %u\n", info->match_set.index); + optind++; + + *flags = 1; + break; + } + + return 1; +} + +static void +set_printv3_counter(const struct ip_set_counter_match *c, const char *name, + const char *sep) +{ + switch (c->op) { + case IPSET_COUNTER_EQ: + printf(" %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_NE: + printf(" ! %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_LT: + printf(" %s%s-lt %llu", sep, name, c->value); + break; + case IPSET_COUNTER_GT: + printf(" %s%s-gt %llu", sep, name, c->value); + break; + } +} + +static void +set_print_v3_matchinfo(const struct xt_set_info_match_v3 *info, + const char *opt, const char *sep) +{ + print_match(opt, &info->match_set); + if (info->flags & IPSET_FLAG_RETURN_NOMATCH) + printf(" %sreturn-nomatch", sep); + if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) + printf(" ! %supdate-counters", sep); + if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)) + printf(" ! %supdate-subcounters", sep); + set_printv3_counter(&info->packets, "packets", sep); + set_printv3_counter(&info->bytes, "bytes", sep); +} + +/* Prints out the matchinfo. */ +static void +set_print_v3(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_set_info_match_v3 *info = (const void *)match->data; + + set_print_v3_matchinfo(info, "match-set", ""); +} + +static void +set_save_v3(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_set_info_match_v3 *info = (const void *)match->data; + + set_print_v3_matchinfo(info, "--match-set", "--"); +} + static struct xtables_match set_mt_reg[] = { { .name = "set", @@ -332,6 +540,20 @@ static struct xtables_match set_mt_reg[] = { .save = set_save_v2, .extra_opts = set_opts_v2, }, + { + .name = "set", + .revision = 3, + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_set_info_match_v3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v3)), + .help = set_help_v3, + .parse = set_parse_v3, + .final_check = set_check_v0, + .print = set_print_v3, + .save = set_save_v3, + .extra_opts = set_opts_v3, + }, }; void _init(void) -- cgit v1.2.3