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