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