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