libxt_u32.c revision 373e8513c4b9b0491e46ae89397ead03d093ee76
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 <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 21enum { 22 O_U32 = 0, 23}; 24 25static const struct xt_option_entry u32_opts[] = { 26 {.name = "u32", .id = O_U32, .type = XTTYPE_STRING}, 27 XTOPT_TABLEEND, 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 printf(" \""); 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 } 84 putchar('\"'); 85} 86 87/* string_to_number() is not quite what we need here ... */ 88static uint32_t parse_number(const char **s, int pos) 89{ 90 uint32_t number; 91 char *end; 92 93 errno = 0; 94 number = strtoul(*s, &end, 0); 95 if (end == *s) 96 xtables_error(PARAMETER_PROBLEM, 97 "u32: at char %d: expected number", pos); 98 if (errno != 0) 99 xtables_error(PARAMETER_PROBLEM, 100 "u32: at char %d: error reading number", pos); 101 *s = end; 102 return number; 103} 104 105static void u32_parse(struct xt_option_call *cb) 106{ 107 struct xt_u32 *data = cb->data; 108 unsigned int testind = 0, locind = 0, valind = 0; 109 struct xt_u32_test *ct = &data->tests[testind]; /* current test */ 110 const char *arg = cb->arg; /* the argument string */ 111 const char *start = cb->arg; 112 int state = 0; 113 114 xtables_option_parse(cb); 115 data->invert = cb->invert; 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) 130 xtables_error(PARAMETER_PROBLEM, 131 "u32: abrupt end of input after location specifier"); 132 if (valind == 0) 133 xtables_error(PARAMETER_PROBLEM, 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) 141 xtables_error(PARAMETER_PROBLEM, 142 "u32: at char %u: too many \"&&\"s", 143 (unsigned int)(arg - start)); 144 return; 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) { 154 xtables_error(PARAMETER_PROBLEM, 155 "u32: at char %u: " 156 "location spec missing", 157 (unsigned int)(arg - start)); 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 != '<') 169 xtables_error(PARAMETER_PROBLEM, 170 "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start)); 171 ct->location[locind].nextop = XT_U32_LEFTSH; 172 } else if (*arg == '>') { 173 if (*++arg != '>') 174 xtables_error(PARAMETER_PROBLEM, 175 "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start)); 176 ct->location[locind].nextop = XT_U32_RIGHTSH; 177 } else if (*arg == '@') { 178 ct->location[locind].nextop = XT_U32_AT; 179 } else { 180 xtables_error(PARAMETER_PROBLEM, 181 "u32: at char %u: operator expected", (unsigned int)(arg - start)); 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) 189 xtables_error(PARAMETER_PROBLEM, 190 "u32: at char %u: too many operators", (unsigned int)(arg - start)); 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 != '&') 200 xtables_error(PARAMETER_PROBLEM, 201 "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start)); 202 if (valind == 0) { 203 xtables_error(PARAMETER_PROBLEM, 204 "u32: at char %u: value spec missing", (unsigned int)(arg - start)); 205 } else { 206 ct->nnums = locind; 207 ct->nvalues = valind; 208 ct = &data->tests[++testind]; 209 if (testind > XT_U32_MAXSIZE) 210 xtables_error(PARAMETER_PROBLEM, 211 "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start)); 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 != ',') 220 xtables_error(PARAMETER_PROBLEM, 221 "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start)); 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) 240 xtables_error(PARAMETER_PROBLEM, 241 "u32: at char %u: too many \",\"s", (unsigned int)(arg - start)); 242 } 243 } 244 } 245} 246 247static 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; 251 printf(" u32"); 252 if (data->invert) 253 printf(" !"); 254 u32_dump(data); 255} 256 257static 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) 261 printf(" !"); 262 printf(" --u32"); 263 u32_dump(data); 264} 265 266static struct xtables_match u32_match = { 267 .name = "u32", 268 .family = NFPROTO_UNSPEC, 269 .version = XTABLES_VERSION, 270 .size = XT_ALIGN(sizeof(struct xt_u32)), 271 .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), 272 .help = u32_help, 273 .print = u32_print, 274 .save = u32_save, 275 .x6_parse = u32_parse, 276 .x6_options = u32_opts, 277}; 278 279void _init(void) 280{ 281 xtables_register_match(&u32_match); 282} 283