1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/* Shared library add-on to iptables to add packet length matching support. */
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include <linux/netfilter/xt_length.h>
static void length_help(void)
{
printf(
"length match options:\n"
"[!] --length length[:length] Match packet length against value or range\n"
" of values (inclusive)\n");
}
static const struct option length_opts[] = {
{ "length", 1, NULL, '1' },
{ .name = NULL }
};
static u_int16_t
parse_length(const char *s)
{
unsigned int len;
if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX))
xtables_error(PARAMETER_PROBLEM, "length invalid: \"%s\"\n", s);
else
return len;
}
/* If a single value is provided, min and max are both set to the value */
static void
parse_lengths(const char *s, struct xt_length_info *info)
{
char *buffer;
char *cp;
buffer = strdup(s);
if ((cp = strchr(buffer, ':')) == NULL)
info->min = info->max = parse_length(buffer);
else {
*cp = '\0';
cp++;
info->min = buffer[0] ? parse_length(buffer) : 0;
info->max = cp[0] ? parse_length(cp) : 0xFFFF;
}
free(buffer);
if (info->min > info->max)
xtables_error(PARAMETER_PROBLEM,
"length min. range value `%u' greater than max. "
"range value `%u'", info->min, info->max);
}
static int
length_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_length_info *info = (struct xt_length_info *)(*match)->data;
switch (c) {
case '1':
if (*flags)
xtables_error(PARAMETER_PROBLEM,
"length: `--length' may only be "
"specified once");
xtables_check_inverse(optarg, &invert, &optind, 0, argv);
parse_lengths(optarg, info);
if (invert)
info->invert = 1;
*flags = 1;
break;
default:
return 0;
}
return 1;
}
static void length_check(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
"length: You must specify `--length'");
}
static void
length_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_length_info *info = (void *)match->data;
printf("length %s", info->invert ? "!" : "");
if (info->min == info->max)
printf("%u ", info->min);
else
printf("%u:%u ", info->min, info->max);
}
static void length_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_length_info *info = (void *)match->data;
printf("%s--length ", info->invert ? "! " : "");
if (info->min == info->max)
printf("%u ", info->min);
else
printf("%u:%u ", info->min, info->max);
}
static struct xtables_match length_match = {
.family = NFPROTO_UNSPEC,
.name = "length",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_length_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_length_info)),
.help = length_help,
.parse = length_parse,
.final_check = length_check,
.print = length_print,
.save = length_save,
.extra_opts = length_opts,
};
void _init(void)
{
xtables_register_match(&length_match);
}
|