diff options
Diffstat (limited to 'extensions/libxt_connlimit.c')
-rw-r--r-- | extensions/libxt_connlimit.c | 248 |
1 files changed, 142 insertions, 106 deletions
diff --git a/extensions/libxt_connlimit.c b/extensions/libxt_connlimit.c index a215915..a569f86 100644 --- a/extensions/libxt_connlimit.c +++ b/extensions/libxt_connlimit.c @@ -1,27 +1,50 @@ -/* Shared library add-on to iptables to add connection limit support. */ #include <stdio.h> #include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter/xt_connlimit.h> +enum { + O_UPTO = 0, + O_ABOVE, + O_MASK, + O_SADDR, + O_DADDR, + F_UPTO = 1 << O_UPTO, + F_ABOVE = 1 << O_ABOVE, + F_MASK = 1 << O_MASK, + F_SADDR = 1 << O_SADDR, + F_DADDR = 1 << O_DADDR, +}; + static void connlimit_help(void) { printf( "connlimit match options:\n" -"[!] --connlimit-above n match if the number of existing " -" connections is (not) above n\n" -" --connlimit-mask n group hosts using mask\n"); +" --connlimit-upto n match if the number of existing connections is 0..n\n" +" --connlimit-above n match if the number of existing connections is >n\n" +" --connlimit-mask n group hosts using prefix length (default: max len)\n" +" --connlimit-saddr select source address for grouping\n" +" --connlimit-daddr select destination addresses for grouping\n"); } -static const struct option connlimit_opts[] = { - {"connlimit-above", 1, NULL, 'A'}, - {"connlimit-mask", 1, NULL, 'M'}, - { .name = NULL } +#define s struct xt_connlimit_info +static const struct xt_option_entry connlimit_opts[] = { + {.name = "connlimit-upto", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, limit)}, + {.name = "connlimit-above", .id = O_ABOVE, .excl = F_UPTO, + .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, limit)}, + {.name = "connlimit-mask", .id = O_MASK, .type = XTTYPE_PLENMASK, + .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)}, + {.name = "connlimit-saddr", .id = O_SADDR, .excl = F_DADDR, + .type = XTTYPE_NONE}, + {.name = "connlimit-daddr", .id = O_DADDR, .excl = F_SADDR, + .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void connlimit_init(struct xt_entry_match *match) { @@ -31,99 +54,57 @@ static void connlimit_init(struct xt_entry_match *match) memset(info->v6_mask, 0xFF, sizeof(info->v6_mask)); } -static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len) -{ - if (prefix_len == 0) { - mask[0] = mask[1] = mask[2] = mask[3] = 0; - } else if (prefix_len <= 32) { - mask[0] <<= 32 - prefix_len; - mask[1] = mask[2] = mask[3] = 0; - } else if (prefix_len <= 64) { - mask[1] <<= 32 - (prefix_len - 32); - mask[2] = mask[3] = 0; - } else if (prefix_len <= 96) { - mask[2] <<= 32 - (prefix_len - 64); - mask[3] = 0; - } else if (prefix_len <= 128) { - mask[3] <<= 32 - (prefix_len - 96); - } - mask[0] = htonl(mask[0]); - mask[1] = htonl(mask[1]); - mask[2] = htonl(mask[2]); - mask[3] = htonl(mask[3]); -} - -static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags, - struct xt_connlimit_info *info, unsigned int family) +static void connlimit_parse(struct xt_option_call *cb, uint8_t family) { - char *err; - int i; - - switch (c) { - case 'A': - if (*flags & 0x1) + struct xt_connlimit_info *info = cb->data; + const unsigned int revision = (*cb->match)->u.user.revision; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_ABOVE: + if (cb->invert) + info->flags |= XT_CONNLIMIT_INVERT; + break; + case O_UPTO: + if (!cb->invert) + info->flags |= XT_CONNLIMIT_INVERT; + break; + case O_SADDR: + if (revision < 1) xtables_error(PARAMETER_PROBLEM, - "--connlimit-above may be given only once"); - *flags |= 0x1; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->limit = strtoul(optarg, NULL, 0); - info->inverse = invert; + "xt_connlimit.0 does not support " + "--connlimit-daddr"); + info->flags &= ~XT_CONNLIMIT_DADDR; break; - case 'M': - if (*flags & 0x2) + case O_DADDR: + if (revision < 1) xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask may be given only once"); - - *flags |= 0x2; - i = strtoul(optarg, &err, 0); - if (family == NFPROTO_IPV6) { - if (i > 128 || *err != '\0') - xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask must be between " - "0 and 128"); - prefix_to_netmask(info->v6_mask, i); - } else { - if (i > 32 || *err != '\0') - xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask must be between " - "0 and 32"); - if (i == 0) - info->v4_mask = 0; - else - info->v4_mask = htonl(0xFFFFFFFF << (32 - i)); - } + "xt_connlimit.0 does not support " + "--connlimit-daddr"); + info->flags |= XT_CONNLIMIT_DADDR; break; - default: - return 0; } - - return 1; } -static int connlimit_parse4(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_match **match) +static void connlimit_parse4(struct xt_option_call *cb) { - return connlimit_parse(c, argv, invert, flags, - (void *)(*match)->data, NFPROTO_IPV4); + return connlimit_parse(cb, NFPROTO_IPV4); } -static int connlimit_parse6(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_match **match) +static void connlimit_parse6(struct xt_option_call *cb) { - return connlimit_parse(c, argv, invert, flags, - (void *)(*match)->data, NFPROTO_IPV6); + return connlimit_parse(cb, NFPROTO_IPV6); } -static void connlimit_check(unsigned int flags) +static void connlimit_check(struct xt_fcheck_call *cb) { - if (!(flags & 0x1)) + if ((cb->xflags & (F_UPTO | F_ABOVE)) == 0) xtables_error(PARAMETER_PROBLEM, - "You must specify \"--connlimit-above\""); + "You must specify \"--connlimit-above\" or " + "\"--connlimit-upto\"."); } -static unsigned int count_bits4(u_int32_t mask) +static unsigned int count_bits4(uint32_t mask) { unsigned int bits = 0; @@ -133,10 +114,10 @@ static unsigned int count_bits4(u_int32_t mask) return 32 - bits; } -static unsigned int count_bits6(const u_int32_t *mask) +static unsigned int count_bits6(const uint32_t *mask) { unsigned int bits = 0, i; - u_int32_t tmp[4]; + uint32_t tmp[4]; for (i = 0; i < 4; ++i) for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1) @@ -149,64 +130,119 @@ static void connlimit_print4(const void *ip, { const struct xt_connlimit_info *info = (const void *)match->data; - printf("#conn/%u %s %u ", count_bits4(info->v4_mask), - info->inverse ? "<=" : ">", info->limit); + printf(" #conn %s/%u %s %u", + (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", + count_bits4(info->v4_mask), + (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); } static void connlimit_print6(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_connlimit_info *info = (const void *)match->data; - printf("#conn/%u %s %u ", count_bits6(info->v6_mask), - info->inverse ? "<=" : ">", info->limit); + + printf(" #conn %s/%u %s %u", + (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", + count_bits6(info->v6_mask), + (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); } static void connlimit_save4(const void *ip, const struct xt_entry_match *match) { const struct xt_connlimit_info *info = (const void *)match->data; - - printf("%s--connlimit-above %u --connlimit-mask %u ", - info->inverse ? "! " : "", info->limit, - count_bits4(info->v4_mask)); + const int revision = match->u.user.revision; + + if (info->flags & XT_CONNLIMIT_INVERT) + printf(" --connlimit-upto %u", info->limit); + else + printf(" --connlimit-above %u", info->limit); + printf(" --connlimit-mask %u", count_bits4(info->v4_mask)); + if (revision >= 1) { + if (info->flags & XT_CONNLIMIT_DADDR) + printf(" --connlimit-daddr"); + else + printf(" --connlimit-saddr"); + } } static void connlimit_save6(const void *ip, const struct xt_entry_match *match) { const struct xt_connlimit_info *info = (const void *)match->data; - - printf("%s--connlimit-above %u --connlimit-mask %u ", - info->inverse ? "! " : "", info->limit, - count_bits6(info->v6_mask)); + const int revision = match->u.user.revision; + + if (info->flags & XT_CONNLIMIT_INVERT) + printf(" --connlimit-upto %u", info->limit); + else + printf(" --connlimit-above %u", info->limit); + printf(" --connlimit-mask %u", count_bits6(info->v6_mask)); + if (revision >= 1) { + if (info->flags & XT_CONNLIMIT_DADDR) + printf(" --connlimit-daddr"); + else + printf(" --connlimit-saddr"); + } } static struct xtables_match connlimit_mt_reg[] = { { .name = "connlimit", + .revision = 0, + .family = NFPROTO_IPV4, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), + .userspacesize = offsetof(struct xt_connlimit_info, data), + .help = connlimit_help, + .init = connlimit_init, + .x6_parse = connlimit_parse4, + .x6_fcheck = connlimit_check, + .print = connlimit_print4, + .save = connlimit_save4, + .x6_options = connlimit_opts, + }, + { + .name = "connlimit", + .revision = 0, + .family = NFPROTO_IPV6, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), + .userspacesize = offsetof(struct xt_connlimit_info, data), + .help = connlimit_help, + .init = connlimit_init, + .x6_parse = connlimit_parse6, + .x6_fcheck = connlimit_check, + .print = connlimit_print6, + .save = connlimit_save6, + .x6_options = connlimit_opts, + }, + { + .name = "connlimit", + .revision = 1, .family = NFPROTO_IPV4, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), .userspacesize = offsetof(struct xt_connlimit_info, data), .help = connlimit_help, .init = connlimit_init, - .parse = connlimit_parse4, - .final_check = connlimit_check, + .x6_parse = connlimit_parse4, + .x6_fcheck = connlimit_check, .print = connlimit_print4, .save = connlimit_save4, - .extra_opts = connlimit_opts, + .x6_options = connlimit_opts, }, { .name = "connlimit", + .revision = 1, .family = NFPROTO_IPV6, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), .userspacesize = offsetof(struct xt_connlimit_info, data), .help = connlimit_help, .init = connlimit_init, - .parse = connlimit_parse6, - .final_check = connlimit_check, + .x6_parse = connlimit_parse6, + .x6_fcheck = connlimit_check, .print = connlimit_print6, .save = connlimit_save6, - .extra_opts = connlimit_opts, + .x6_options = connlimit_opts, }, }; |