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