From 9640e529bd08c4c0458246fae0fd6b473c94ab46 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 10 Sep 2007 11:50:46 +0000 Subject: Adds u32 to iptables. Signed-off-by: Jan Engelhardt --- extensions/libxt_u32.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 extensions/libxt_u32.c (limited to 'extensions/libxt_u32.c') diff --git a/extensions/libxt_u32.c b/extensions/libxt_u32.c new file mode 100644 index 00000000..e2642f39 --- /dev/null +++ b/extensions/libxt_u32.c @@ -0,0 +1,307 @@ +/* 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 + * Copyright © Jan Engelhardt , 2007 + * Released under the terms of GNU GPL v2 + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../include/linux/netfilter/xt_u32.h" + +static const struct option u32_opts[] = { + {"u32", 1, NULL, 'u'}, + {NULL}, +}; + +static void u32_help(void) +{ + printf( + "u32 v%s 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", + IPTABLES_VERSION); + return; +} + +static void u32_dump(const struct xt_u32 *data) +{ + const struct xt_u32_test *ct; + unsigned int testind, i; + + 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); + } + } + printf(" "); +} + +/* string_to_number() is not quite what we need here ... */ +static u_int32_t parse_number(char **s, int pos) +{ + u_int32_t number; + char *end; + + errno = 0; + number = strtoul(*s, &end, 0); + if (end == *s) + exit_error(PARAMETER_PROBLEM, + "u32: at char %d: expected number", pos); + if (errno != 0) + exit_error(PARAMETER_PROBLEM, + "u32: at char %d: error reading number", pos); + *s = end; + return number; +} + +/* Function which parses command options; returns true if it ate an option */ +static int u32_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_u32 *data = (void *)(*match)->data; + unsigned int testind = 0, locind = 0, valind = 0; + struct xt_u32_test *ct = &data->tests[testind]; /* current test */ + char *arg = argv[optind-1]; /* the argument string */ + char *start = arg; + int state = 0; + + if (c != 'u') + return 0; + + data->invert = 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) + exit_error(PARAMETER_PROBLEM, + "u32: abrupt end of input after location specifier"); + if (valind == 0) + exit_error(PARAMETER_PROBLEM, + "u32: test ended with no value specified"); + + ct->nnums = locind; + ct->nvalues = valind; + data->ntests = ++testind; + + if (testind > XT_U32_MAXSIZE) + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: too many \"&&\"s", + arg - start); + return 1; + } + + 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) { + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: " + "location spec missing", + 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 != '<') + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: a second < expected", arg - start); + ct->location[locind].nextop = XT_U32_LEFTSH; + } else if (*arg == '>') { + if (*++arg != '>') + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: a second > expected", arg - start); + ct->location[locind].nextop = XT_U32_RIGHTSH; + } else if (*arg == '@') { + ct->location[locind].nextop = XT_U32_AT; + } else { + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: operator expected", 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) + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: too many operators", 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 != '&') + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: a second & was expected", arg - start); + if (valind == 0) { + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: value spec missing", arg - start); + } else { + ct->nnums = locind; + ct->nvalues = valind; + ct = &data->tests[++testind]; + if (testind > XT_U32_MAXSIZE) + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: too many \"&&\"s", arg - start); + ++arg; + state = 0; + locind = 0; + valind = 0; + } + } else { /* read value range */ + if (valind > 0) { /* need , before number */ + if (*arg != ',') + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: expected , or &&", 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) + exit_error(PARAMETER_PROBLEM, + "u32: at char %ld: too many \",\"s", arg - start); + } + } + } +} + +static void u32_check(unsigned int flags) +{ +} + +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); + return; +} + +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); + return; +} + +static struct xtables_match u32_reg = { + .name = "u32", + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_u32)), + .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), + .help = u32_help, + .parse = u32_parse, + .final_check = u32_check, + .print = u32_print, + .save = u32_save, + .extra_opts = u32_opts, +}; + +static struct xtables_match u32_reg6 = { + .name = "u32", + .family = AF_INET6, + .version = IPTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_u32)), + .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), + .help = u32_help, + .parse = u32_parse, + .final_check = u32_check, + .print = u32_print, + .save = u32_save, + .extra_opts = u32_opts, +}; + +void _init(void) +{ + xtables_register_match(&u32_reg); + xtables_register_match(&u32_reg6); + return; +} -- cgit v1.2.3