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