#include #include #include #include #include #include #include "xt_length2.h" #include "compat_user.h" enum { F_LAYER = 1 << 0, F_LENGTH = 1 << 1, XT_LENGTH_LAYER_MASK = XT_LENGTH_LAYER3 | XT_LENGTH_LAYER4 | XT_LENGTH_LAYER5 | XT_LENGTH_LAYER7, }; static void length_mt_help(void) { printf( "length match options:\n" " --layer3 Match against layer3 size (e.g. L4 + IPv6 header)\n" " --layer4 Match against layer4 size (e.g. L5 + SCTP header)\n" " --layer5 Match against layer5 size (e.g. L7 + chunk headers)\n" " --layer7 Match against layer7 payload (e.g. SCTP payload)\n" "[!] --length n[:n] Match packet length against value or range\n" " of values (inclusive)\n" ); } static const struct option length_mt_opts[] = { {.name = "layer3", .has_arg = false, .val = '3'}, {.name = "layer4", .has_arg = false, .val = '4'}, {.name = "layer5", .has_arg = false, .val = '5'}, {.name = "layer7", .has_arg = false, .val = '7'}, {.name = "length", .has_arg = true, .val = '='}, {NULL}, }; static void length_mt_init(struct xt_entry_match *match) { struct xt_length_mtinfo2 *info = (void *)match->data; info->flags = XT_LENGTH_LAYER3; } static int length_mt_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_length_mtinfo2 *info = (void *)(*match)->data; unsigned int from, to; char *end; switch (c) { case '3': /* --layer3 */ xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER); info->flags &= ~XT_LENGTH_LAYER_MASK; info->flags |= XT_LENGTH_LAYER3; *flags |= F_LAYER; return true; case '4': /* --layer4 */ xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER); info->flags &= ~XT_LENGTH_LAYER_MASK; info->flags |= XT_LENGTH_LAYER4; *flags |= F_LAYER; return true; case '5': /* --layer5 */ xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER); info->flags &= ~XT_LENGTH_LAYER_MASK; info->flags |= XT_LENGTH_LAYER5; *flags |= F_LAYER; return true; case '7': /* --layer7 */ xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER); info->flags &= ~XT_LENGTH_LAYER_MASK; info->flags |= XT_LENGTH_LAYER7; *flags |= F_LAYER; return true; case '=': /* --length */ xtables_param_act(XTF_ONLY_ONCE, "length", "--length", *flags & F_LENGTH); if (invert) info->flags |= XT_LENGTH_INVERT; if (!xtables_strtoui(optarg, &end, &from, 0, ~0U)) xtables_param_act(XTF_BAD_VALUE, "length", "--length", optarg); to = from; if (*end == ':') if (!xtables_strtoui(end + 1, &end, &to, 0, ~0U)) xtables_param_act(XTF_BAD_VALUE, "length", "--length", optarg); if (*end != '\0') xtables_param_act(XTF_BAD_VALUE, "length", "--length", optarg); info->min = from; info->max = to; *flags |= F_LENGTH; return true; } return false; } static void length_mt_check(unsigned int flags) { if (!(flags & F_LENGTH)) xtables_error(PARAMETER_PROBLEM, "length: You must specify \"--length\""); if (!(flags & F_LAYER)) fprintf(stderr, "iptables: length match: Defaulting to " "--layer3. Consider specifying it explicitly.\n"); } static void length_mt_save(const void *ip, const struct xt_entry_match *match) { const struct xt_length_mtinfo2 *info = (const void *)match->data; if (info->flags & XT_LENGTH_LAYER3) printf(" --layer3 "); else if (info->flags & XT_LENGTH_LAYER4) printf(" --layer4 "); else if (info->flags & XT_LENGTH_LAYER5) printf(" --layer5 "); else if (info->flags & XT_LENGTH_LAYER7) printf(" --layer7 "); if (info->flags & XT_LENGTH_INVERT) printf(" !"); printf(" --length "); if (info->min == info->max) printf("%u ", (unsigned int)info->min); else printf("%u:%u ", (unsigned int)info->min, (unsigned int)info->max); } static void length_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) { printf(" -m length2"); length_mt_save(ip, match); } static struct xtables_match length2_mt_reg = { .version = XTABLES_VERSION, .name = "length2", .revision = 2, .family = NFPROTO_UNSPEC, .size = XT_ALIGN(sizeof(struct xt_length_mtinfo2)), .userspacesize = XT_ALIGN(sizeof(struct xt_length_mtinfo2)), .init = length_mt_init, .help = length_mt_help, .parse = length_mt_parse, .final_check = length_mt_check, .print = length_mt_print, .save = length_mt_save, .extra_opts = length_mt_opts, }; static void _init(void) { xtables_register_match(&length2_mt_reg); }