Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 1 | /* Shared library add-on to iptables to add u32 matching, |
| 2 | * generalized matching on values found at packet offsets |
| 3 | * |
| 4 | * Detailed doc is in the kernel module source |
| 5 | * net/netfilter/xt_u32.c |
| 6 | * |
| 7 | * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com> |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 8 | * Released under the terms of GNU GPL v2 |
Jan Engelhardt | 032722b | 2007-10-20 15:17:30 +0000 | [diff] [blame] | 9 | * |
| 10 | * Copyright © CC Computer Consultants GmbH, 2007 |
| 11 | * Contact: <jengelh@computergmbh.de> |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 12 | */ |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 13 | #include <ctype.h> |
| 14 | #include <errno.h> |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 15 | #include <stdint.h> |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 16 | #include <stdlib.h> |
| 17 | #include <stdio.h> |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 18 | #include <xtables.h> |
Jan Engelhardt | a2a7f2b | 2008-09-01 14:20:13 +0200 | [diff] [blame] | 19 | #include <linux/netfilter/xt_u32.h> |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 20 | |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 21 | enum { |
| 22 | O_U32 = 0, |
| 23 | }; |
| 24 | |
| 25 | static const struct xt_option_entry u32_opts[] = { |
| 26 | {.name = "u32", .id = O_U32, .type = XTTYPE_STRING}, |
| 27 | XTOPT_TABLEEND, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 28 | }; |
| 29 | |
| 30 | static void u32_help(void) |
| 31 | { |
| 32 | printf( |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 33 | "u32 match options:\n" |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 34 | "[!] --u32 tests\n" |
| 35 | "\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n" |
| 36 | "\t\t""value := range | value \",\" range\n" |
| 37 | "\t\t""range := number | number \":\" number\n" |
| 38 | "\t\t""location := number | location operator number\n" |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 39 | "\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n"); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 40 | } |
| 41 | |
| 42 | static void u32_dump(const struct xt_u32 *data) |
| 43 | { |
| 44 | const struct xt_u32_test *ct; |
| 45 | unsigned int testind, i; |
| 46 | |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 47 | printf(" \""); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 48 | for (testind = 0; testind < data->ntests; ++testind) { |
| 49 | ct = &data->tests[testind]; |
| 50 | |
| 51 | if (testind > 0) |
| 52 | printf("&&"); |
| 53 | |
| 54 | printf("0x%x", ct->location[0].number); |
| 55 | for (i = 1; i < ct->nnums; ++i) { |
| 56 | switch (ct->location[i].nextop) { |
| 57 | case XT_U32_AND: |
| 58 | printf("&"); |
| 59 | break; |
| 60 | case XT_U32_LEFTSH: |
| 61 | printf("<<"); |
| 62 | break; |
| 63 | case XT_U32_RIGHTSH: |
| 64 | printf(">>"); |
| 65 | break; |
| 66 | case XT_U32_AT: |
| 67 | printf("@"); |
| 68 | break; |
| 69 | } |
| 70 | printf("0x%x", ct->location[i].number); |
| 71 | } |
| 72 | |
| 73 | printf("="); |
| 74 | for (i = 0; i < ct->nvalues; ++i) { |
| 75 | if (i > 0) |
| 76 | printf(","); |
| 77 | if (ct->value[i].min == ct->value[i].max) |
| 78 | printf("0x%x", ct->value[i].min); |
| 79 | else |
| 80 | printf("0x%x:0x%x", ct->value[i].min, |
| 81 | ct->value[i].max); |
| 82 | } |
| 83 | } |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 84 | putchar('\"'); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | /* string_to_number() is not quite what we need here ... */ |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 88 | static uint32_t parse_number(const char **s, int pos) |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 89 | { |
Jan Engelhardt | 7ac4052 | 2011-01-07 12:34:04 +0100 | [diff] [blame] | 90 | uint32_t number; |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 91 | char *end; |
| 92 | |
| 93 | errno = 0; |
| 94 | number = strtoul(*s, &end, 0); |
| 95 | if (end == *s) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 96 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 97 | "u32: at char %d: expected number", pos); |
| 98 | if (errno != 0) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 99 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 100 | "u32: at char %d: error reading number", pos); |
| 101 | *s = end; |
| 102 | return number; |
| 103 | } |
| 104 | |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 105 | static void u32_parse(struct xt_option_call *cb) |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 106 | { |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 107 | struct xt_u32 *data = cb->data; |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 108 | unsigned int testind = 0, locind = 0, valind = 0; |
| 109 | struct xt_u32_test *ct = &data->tests[testind]; /* current test */ |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 110 | const char *arg = cb->arg; /* the argument string */ |
| 111 | const char *start = cb->arg; |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 112 | int state = 0; |
| 113 | |
Jan Engelhardt | 373e851 | 2011-05-06 22:40:35 +0200 | [diff] [blame] | 114 | xtables_option_parse(cb); |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 115 | data->invert = cb->invert; |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 116 | |
| 117 | /* |
| 118 | * states: |
| 119 | * 0 = looking for numbers and operations, |
| 120 | * 1 = looking for ranges |
| 121 | */ |
| 122 | while (1) { |
| 123 | /* read next operand/number or range */ |
| 124 | while (isspace(*arg)) |
| 125 | ++arg; |
| 126 | |
| 127 | if (*arg == '\0') { |
| 128 | /* end of argument found */ |
| 129 | if (state == 0) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 130 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 131 | "u32: abrupt end of input after location specifier"); |
| 132 | if (valind == 0) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 133 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 134 | "u32: test ended with no value specified"); |
| 135 | |
| 136 | ct->nnums = locind; |
| 137 | ct->nvalues = valind; |
| 138 | data->ntests = ++testind; |
| 139 | |
| 140 | if (testind > XT_U32_MAXSIZE) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 141 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 142 | "u32: at char %u: too many \"&&\"s", |
| 143 | (unsigned int)(arg - start)); |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 144 | return; |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 145 | } |
| 146 | |
| 147 | if (state == 0) { |
| 148 | /* |
| 149 | * reading location: read a number if nothing read yet, |
| 150 | * otherwise either op number or = to end location spec |
| 151 | */ |
| 152 | if (*arg == '=') { |
| 153 | if (locind == 0) { |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 154 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 155 | "u32: at char %u: " |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 156 | "location spec missing", |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 157 | (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 158 | } else { |
| 159 | ++arg; |
| 160 | state = 1; |
| 161 | } |
| 162 | } else { |
| 163 | if (locind != 0) { |
| 164 | /* need op before number */ |
| 165 | if (*arg == '&') { |
| 166 | ct->location[locind].nextop = XT_U32_AND; |
| 167 | } else if (*arg == '<') { |
| 168 | if (*++arg != '<') |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 169 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 170 | "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 171 | ct->location[locind].nextop = XT_U32_LEFTSH; |
| 172 | } else if (*arg == '>') { |
| 173 | if (*++arg != '>') |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 174 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 175 | "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 176 | ct->location[locind].nextop = XT_U32_RIGHTSH; |
| 177 | } else if (*arg == '@') { |
| 178 | ct->location[locind].nextop = XT_U32_AT; |
| 179 | } else { |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 180 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 181 | "u32: at char %u: operator expected", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 182 | } |
| 183 | ++arg; |
| 184 | } |
| 185 | /* now a number; string_to_number skips white space? */ |
| 186 | ct->location[locind].number = |
| 187 | parse_number(&arg, arg - start); |
| 188 | if (++locind > XT_U32_MAXSIZE) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 189 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 190 | "u32: at char %u: too many operators", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 191 | } |
| 192 | } else { |
| 193 | /* |
| 194 | * state 1 - reading values: read a range if nothing |
| 195 | * read yet, otherwise either ,range or && to end |
| 196 | * test spec |
| 197 | */ |
| 198 | if (*arg == '&') { |
| 199 | if (*++arg != '&') |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 200 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 201 | "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 202 | if (valind == 0) { |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 203 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 204 | "u32: at char %u: value spec missing", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 205 | } else { |
| 206 | ct->nnums = locind; |
| 207 | ct->nvalues = valind; |
| 208 | ct = &data->tests[++testind]; |
| 209 | if (testind > XT_U32_MAXSIZE) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 210 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 211 | "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 212 | ++arg; |
| 213 | state = 0; |
| 214 | locind = 0; |
| 215 | valind = 0; |
| 216 | } |
| 217 | } else { /* read value range */ |
| 218 | if (valind > 0) { /* need , before number */ |
| 219 | if (*arg != ',') |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 220 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 221 | "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 222 | ++arg; |
| 223 | } |
| 224 | ct->value[valind].min = |
| 225 | parse_number(&arg, arg - start); |
| 226 | |
| 227 | while (isspace(*arg)) |
| 228 | ++arg; |
| 229 | |
| 230 | if (*arg == ':') { |
| 231 | ++arg; |
| 232 | ct->value[valind].max = |
| 233 | parse_number(&arg, arg-start); |
| 234 | } else { |
| 235 | ct->value[valind].max = |
| 236 | ct->value[valind].min; |
| 237 | } |
| 238 | |
| 239 | if (++valind > XT_U32_MAXSIZE) |
Jan Engelhardt | 1829ed4 | 2009-02-21 03:29:44 +0100 | [diff] [blame] | 240 | xtables_error(PARAMETER_PROBLEM, |
Jan Engelhardt | 55951a0 | 2007-09-19 12:59:33 +0000 | [diff] [blame] | 241 | "u32: at char %u: too many \",\"s", (unsigned int)(arg - start)); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 242 | } |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 247 | static void u32_print(const void *ip, const struct xt_entry_match *match, |
| 248 | int numeric) |
| 249 | { |
| 250 | const struct xt_u32 *data = (const void *)match->data; |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 251 | printf(" u32"); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 252 | if (data->invert) |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 253 | printf(" !"); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 254 | u32_dump(data); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 255 | } |
| 256 | |
| 257 | static void u32_save(const void *ip, const struct xt_entry_match *match) |
| 258 | { |
| 259 | const struct xt_u32 *data = (const void *)match->data; |
| 260 | if (data->invert) |
Jan Engelhardt | 7386635 | 2010-12-18 02:04:59 +0100 | [diff] [blame] | 261 | printf(" !"); |
| 262 | printf(" --u32"); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 263 | u32_dump(data); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 264 | } |
| 265 | |
Jan Engelhardt | 181dead | 2007-10-04 16:27:07 +0000 | [diff] [blame] | 266 | static struct xtables_match u32_match = { |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 267 | .name = "u32", |
Jan Engelhardt | 4297936 | 2009-06-01 11:56:23 +0200 | [diff] [blame] | 268 | .family = NFPROTO_UNSPEC, |
Jan Engelhardt | 8b7c64d | 2008-04-15 11:48:25 +0200 | [diff] [blame] | 269 | .version = XTABLES_VERSION, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 270 | .size = XT_ALIGN(sizeof(struct xt_u32)), |
| 271 | .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), |
| 272 | .help = u32_help, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 273 | .print = u32_print, |
| 274 | .save = u32_save, |
Jan Engelhardt | 4f7f187 | 2011-03-02 23:06:59 +0100 | [diff] [blame] | 275 | .x6_parse = u32_parse, |
| 276 | .x6_options = u32_opts, |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 277 | }; |
| 278 | |
| 279 | void _init(void) |
| 280 | { |
Jan Engelhardt | 181dead | 2007-10-04 16:27:07 +0000 | [diff] [blame] | 281 | xtables_register_match(&u32_match); |
Jan Engelhardt | 9640e52 | 2007-09-10 11:50:46 +0000 | [diff] [blame] | 282 | } |