123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* Shared library add-on to iptables to add u32 matching,
- * generalized matching on values found at packet offsets
- *
- * Detailed doc is in the kernel module source
- * net/netfilter/xt_u32.c
- *
- * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
- * Released under the terms of GNU GPL v2
- *
- * Copyright © CC Computer Consultants GmbH, 2007
- * Contact: <jengelh@computergmbh.de>
- */
- #include <ctype.h>
- #include <errno.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <xtables.h>
- #include <linux/netfilter/xt_u32.h>
- enum {
- O_U32 = 0,
- };
- static const struct xt_option_entry u32_opts[] = {
- {.name = "u32", .id = O_U32, .type = XTTYPE_STRING,
- .flags = XTOPT_MAND | XTOPT_INVERT},
- XTOPT_TABLEEND,
- };
- static void u32_help(void)
- {
- printf(
- "u32 match options:\n"
- "[!] --u32 tests\n"
- "\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
- "\t\t""value := range | value \",\" range\n"
- "\t\t""range := number | number \":\" number\n"
- "\t\t""location := number | location operator number\n"
- "\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n");
- }
- static void u32_dump(const struct xt_u32 *data)
- {
- const struct xt_u32_test *ct;
- unsigned int testind, i;
- printf(" \"");
- for (testind = 0; testind < data->ntests; ++testind) {
- ct = &data->tests[testind];
- if (testind > 0)
- printf("&&");
- printf("0x%x", ct->location[0].number);
- for (i = 1; i < ct->nnums; ++i) {
- switch (ct->location[i].nextop) {
- case XT_U32_AND:
- printf("&");
- break;
- case XT_U32_LEFTSH:
- printf("<<");
- break;
- case XT_U32_RIGHTSH:
- printf(">>");
- break;
- case XT_U32_AT:
- printf("@");
- break;
- }
- printf("0x%x", ct->location[i].number);
- }
- printf("=");
- for (i = 0; i < ct->nvalues; ++i) {
- if (i > 0)
- printf(",");
- if (ct->value[i].min == ct->value[i].max)
- printf("0x%x", ct->value[i].min);
- else
- printf("0x%x:0x%x", ct->value[i].min,
- ct->value[i].max);
- }
- }
- putchar('\"');
- }
- /* string_to_number() is not quite what we need here ... */
- static uint32_t parse_number(const char **s, int pos)
- {
- unsigned int number;
- char *end;
- if (!xtables_strtoui(*s, &end, &number, 0, UINT32_MAX) ||
- end == *s)
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %d: not a number or out of range", pos);
- *s = end;
- return number;
- }
- static void u32_parse(struct xt_option_call *cb)
- {
- struct xt_u32 *data = cb->data;
- unsigned int testind = 0, locind = 0, valind = 0;
- struct xt_u32_test *ct = &data->tests[testind]; /* current test */
- const char *arg = cb->arg; /* the argument string */
- const char *start = cb->arg;
- int state = 0;
- xtables_option_parse(cb);
- data->invert = cb->invert;
- /*
- * states:
- * 0 = looking for numbers and operations,
- * 1 = looking for ranges
- */
- while (1) {
- /* read next operand/number or range */
- while (isspace(*arg))
- ++arg;
- if (*arg == '\0') {
- /* end of argument found */
- if (state == 0)
- xtables_error(PARAMETER_PROBLEM,
- "u32: abrupt end of input after location specifier");
- if (valind == 0)
- xtables_error(PARAMETER_PROBLEM,
- "u32: test ended with no value specified");
- ct->nnums = locind;
- ct->nvalues = valind;
- data->ntests = ++testind;
- if (testind > XT_U32_MAXSIZE)
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: too many \"&&\"s",
- (unsigned int)(arg - start));
- return;
- }
- if (state == 0) {
- /*
- * reading location: read a number if nothing read yet,
- * otherwise either op number or = to end location spec
- */
- if (*arg == '=') {
- if (locind == 0) {
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: "
- "location spec missing",
- (unsigned int)(arg - start));
- } else {
- ++arg;
- state = 1;
- }
- } else {
- if (locind != 0) {
- /* need op before number */
- if (*arg == '&') {
- ct->location[locind].nextop = XT_U32_AND;
- } else if (*arg == '<') {
- if (*++arg != '<')
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
- ct->location[locind].nextop = XT_U32_LEFTSH;
- } else if (*arg == '>') {
- if (*++arg != '>')
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
- ct->location[locind].nextop = XT_U32_RIGHTSH;
- } else if (*arg == '@') {
- ct->location[locind].nextop = XT_U32_AT;
- } else {
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: operator expected", (unsigned int)(arg - start));
- }
- ++arg;
- }
- /* now a number; string_to_number skips white space? */
- ct->location[locind].number =
- parse_number(&arg, arg - start);
- if (++locind > XT_U32_MAXSIZE)
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: too many operators", (unsigned int)(arg - start));
- }
- } else {
- /*
- * state 1 - reading values: read a range if nothing
- * read yet, otherwise either ,range or && to end
- * test spec
- */
- if (*arg == '&') {
- if (*++arg != '&')
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
- if (valind == 0) {
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: value spec missing", (unsigned int)(arg - start));
- } else {
- ct->nnums = locind;
- ct->nvalues = valind;
- ct = &data->tests[++testind];
- if (testind > XT_U32_MAXSIZE)
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
- ++arg;
- state = 0;
- locind = 0;
- valind = 0;
- }
- } else { /* read value range */
- if (valind > 0) { /* need , before number */
- if (*arg != ',')
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
- ++arg;
- }
- ct->value[valind].min =
- parse_number(&arg, arg - start);
- while (isspace(*arg))
- ++arg;
- if (*arg == ':') {
- ++arg;
- ct->value[valind].max =
- parse_number(&arg, arg-start);
- } else {
- ct->value[valind].max =
- ct->value[valind].min;
- }
- if (++valind > XT_U32_MAXSIZE)
- xtables_error(PARAMETER_PROBLEM,
- "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
- }
- }
- }
- }
- static void u32_print(const void *ip, const struct xt_entry_match *match,
- int numeric)
- {
- const struct xt_u32 *data = (const void *)match->data;
- printf(" u32");
- if (data->invert)
- printf(" !");
- u32_dump(data);
- }
- static void u32_save(const void *ip, const struct xt_entry_match *match)
- {
- const struct xt_u32 *data = (const void *)match->data;
- if (data->invert)
- printf(" !");
- printf(" --u32");
- u32_dump(data);
- }
- static struct xtables_match u32_match = {
- .name = "u32",
- .family = NFPROTO_UNSPEC,
- .version = XTABLES_VERSION,
- .size = XT_ALIGN(sizeof(struct xt_u32)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
- .help = u32_help,
- .print = u32_print,
- .save = u32_save,
- .x6_parse = u32_parse,
- .x6_options = u32_opts,
- };
- void _init(void)
- {
- xtables_register_match(&u32_match);
- }
|