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