libxt_u32.c revision bbe83862a5e1baf15f7c923352d4afdf59bc70e2
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 <linux/netfilter/xt_u32.h> 24 25static const struct option u32_opts[] = { 26 {"u32", 1, NULL, 'u'}, 27 { .name = NULL } 28}; 29 30static void u32_help(void) 31{ 32 printf( 33 "u32 match 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} 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 xtables_error(PARAMETER_PROBLEM, 96 "u32: at char %d: expected number", pos); 97 if (errno != 0) 98 xtables_error(PARAMETER_PROBLEM, 99 "u32: at char %d: error reading number", pos); 100 *s = end; 101 return number; 102} 103 104static int u32_parse(int c, char **argv, int invert, unsigned int *flags, 105 const void *entry, struct xt_entry_match **match) 106{ 107 struct xt_u32 *data = (void *)(*match)->data; 108 unsigned int testind = 0, locind = 0, valind = 0; 109 struct xt_u32_test *ct = &data->tests[testind]; /* current test */ 110 char *arg = optarg; /* the argument string */ 111 char *start = arg; 112 int state = 0; 113 114 if (c != 'u') 115 return 0; 116 117 data->invert = invert; 118 119 /* 120 * states: 121 * 0 = looking for numbers and operations, 122 * 1 = looking for ranges 123 */ 124 while (1) { 125 /* read next operand/number or range */ 126 while (isspace(*arg)) 127 ++arg; 128 129 if (*arg == '\0') { 130 /* end of argument found */ 131 if (state == 0) 132 xtables_error(PARAMETER_PROBLEM, 133 "u32: abrupt end of input after location specifier"); 134 if (valind == 0) 135 xtables_error(PARAMETER_PROBLEM, 136 "u32: test ended with no value specified"); 137 138 ct->nnums = locind; 139 ct->nvalues = valind; 140 data->ntests = ++testind; 141 142 if (testind > XT_U32_MAXSIZE) 143 xtables_error(PARAMETER_PROBLEM, 144 "u32: at char %u: too many \"&&\"s", 145 (unsigned int)(arg - start)); 146 return 1; 147 } 148 149 if (state == 0) { 150 /* 151 * reading location: read a number if nothing read yet, 152 * otherwise either op number or = to end location spec 153 */ 154 if (*arg == '=') { 155 if (locind == 0) { 156 xtables_error(PARAMETER_PROBLEM, 157 "u32: at char %u: " 158 "location spec missing", 159 (unsigned int)(arg - start)); 160 } else { 161 ++arg; 162 state = 1; 163 } 164 } else { 165 if (locind != 0) { 166 /* need op before number */ 167 if (*arg == '&') { 168 ct->location[locind].nextop = XT_U32_AND; 169 } else if (*arg == '<') { 170 if (*++arg != '<') 171 xtables_error(PARAMETER_PROBLEM, 172 "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start)); 173 ct->location[locind].nextop = XT_U32_LEFTSH; 174 } else if (*arg == '>') { 175 if (*++arg != '>') 176 xtables_error(PARAMETER_PROBLEM, 177 "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start)); 178 ct->location[locind].nextop = XT_U32_RIGHTSH; 179 } else if (*arg == '@') { 180 ct->location[locind].nextop = XT_U32_AT; 181 } else { 182 xtables_error(PARAMETER_PROBLEM, 183 "u32: at char %u: operator expected", (unsigned int)(arg - start)); 184 } 185 ++arg; 186 } 187 /* now a number; string_to_number skips white space? */ 188 ct->location[locind].number = 189 parse_number(&arg, arg - start); 190 if (++locind > XT_U32_MAXSIZE) 191 xtables_error(PARAMETER_PROBLEM, 192 "u32: at char %u: too many operators", (unsigned int)(arg - start)); 193 } 194 } else { 195 /* 196 * state 1 - reading values: read a range if nothing 197 * read yet, otherwise either ,range or && to end 198 * test spec 199 */ 200 if (*arg == '&') { 201 if (*++arg != '&') 202 xtables_error(PARAMETER_PROBLEM, 203 "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start)); 204 if (valind == 0) { 205 xtables_error(PARAMETER_PROBLEM, 206 "u32: at char %u: value spec missing", (unsigned int)(arg - start)); 207 } else { 208 ct->nnums = locind; 209 ct->nvalues = valind; 210 ct = &data->tests[++testind]; 211 if (testind > XT_U32_MAXSIZE) 212 xtables_error(PARAMETER_PROBLEM, 213 "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start)); 214 ++arg; 215 state = 0; 216 locind = 0; 217 valind = 0; 218 } 219 } else { /* read value range */ 220 if (valind > 0) { /* need , before number */ 221 if (*arg != ',') 222 xtables_error(PARAMETER_PROBLEM, 223 "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start)); 224 ++arg; 225 } 226 ct->value[valind].min = 227 parse_number(&arg, arg - start); 228 229 while (isspace(*arg)) 230 ++arg; 231 232 if (*arg == ':') { 233 ++arg; 234 ct->value[valind].max = 235 parse_number(&arg, arg-start); 236 } else { 237 ct->value[valind].max = 238 ct->value[valind].min; 239 } 240 241 if (++valind > XT_U32_MAXSIZE) 242 xtables_error(PARAMETER_PROBLEM, 243 "u32: at char %u: too many \",\"s", (unsigned int)(arg - start)); 244 } 245 } 246 } 247} 248 249static void u32_print(const void *ip, const struct xt_entry_match *match, 250 int numeric) 251{ 252 const struct xt_u32 *data = (const void *)match->data; 253 printf("u32 "); 254 if (data->invert) 255 printf("! "); 256 u32_dump(data); 257} 258 259static void u32_save(const void *ip, const struct xt_entry_match *match) 260{ 261 const struct xt_u32 *data = (const void *)match->data; 262 if (data->invert) 263 printf("! "); 264 printf("--u32 "); 265 u32_dump(data); 266} 267 268static struct xtables_match u32_match = { 269 .name = "u32", 270 .family = NFPROTO_UNSPEC, 271 .version = XTABLES_VERSION, 272 .size = XT_ALIGN(sizeof(struct xt_u32)), 273 .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), 274 .help = u32_help, 275 .parse = u32_parse, 276 .print = u32_print, 277 .save = u32_save, 278 .extra_opts = u32_opts, 279}; 280 281void _init(void) 282{ 283 xtables_register_match(&u32_match); 284} 285