blob: f0bb61a3701253bb32abeb34f5125d7c213aff82 [file] [log] [blame]
Jan Engelhardt9640e522007-09-10 11:50:46 +00001/* 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>
Jan Engelhardt9640e522007-09-10 11:50:46 +00008 * Released under the terms of GNU GPL v2
Jan Engelhardt032722b2007-10-20 15:17:30 +00009 *
10 * Copyright © CC Computer Consultants GmbH, 2007
11 * Contact: <jengelh@computergmbh.de>
Jan Engelhardt9640e522007-09-10 11:50:46 +000012 */
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>
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020023#include <linux/netfilter/xt_u32.h>
Jan Engelhardt9640e522007-09-10 11:50:46 +000024
25static const struct option u32_opts[] = {
26 {"u32", 1, NULL, 'u'},
Max Kellermann9ee386a2008-01-29 13:48:05 +000027 { .name = NULL }
Jan Engelhardt9640e522007-09-10 11:50:46 +000028};
29
30static void u32_help(void)
31{
32 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020033 "u32 match options:\n"
Jan Engelhardt9640e522007-09-10 11:50:46 +000034 "[!] --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"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020039 "\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n");
Jan Engelhardt9640e522007-09-10 11:50:46 +000040}
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 exit_error(PARAMETER_PROBLEM,
96 "u32: at char %d: expected number", pos);
97 if (errno != 0)
98 exit_error(PARAMETER_PROBLEM,
99 "u32: at char %d: error reading number", pos);
100 *s = end;
101 return number;
102}
103
Jan Engelhardt9640e522007-09-10 11:50:46 +0000104static 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 = argv[optind-1]; /* 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 exit_error(PARAMETER_PROBLEM,
133 "u32: abrupt end of input after location specifier");
134 if (valind == 0)
135 exit_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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000144 "u32: at char %u: too many \"&&\"s",
145 (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000146 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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000157 "u32: at char %u: "
Jan Engelhardt9640e522007-09-10 11:50:46 +0000158 "location spec missing",
Jan Engelhardt55951a02007-09-19 12:59:33 +0000159 (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000160 } 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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000172 "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000173 ct->location[locind].nextop = XT_U32_LEFTSH;
174 } else if (*arg == '>') {
175 if (*++arg != '>')
176 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000177 "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000178 ct->location[locind].nextop = XT_U32_RIGHTSH;
179 } else if (*arg == '@') {
180 ct->location[locind].nextop = XT_U32_AT;
181 } else {
182 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000183 "u32: at char %u: operator expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000184 }
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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000192 "u32: at char %u: too many operators", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000193 }
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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000203 "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000204 if (valind == 0) {
205 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000206 "u32: at char %u: value spec missing", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000207 } else {
208 ct->nnums = locind;
209 ct->nvalues = valind;
210 ct = &data->tests[++testind];
211 if (testind > XT_U32_MAXSIZE)
212 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000213 "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000214 ++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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000223 "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000224 ++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 exit_error(PARAMETER_PROBLEM,
Jan Engelhardt55951a02007-09-19 12:59:33 +0000243 "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
Jan Engelhardt9640e522007-09-10 11:50:46 +0000244 }
245 }
246 }
247}
248
Jan Engelhardt9640e522007-09-10 11:50:46 +0000249static 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);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000257}
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);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000266}
267
Jan Engelhardt181dead2007-10-04 16:27:07 +0000268static struct xtables_match u32_match = {
Jan Engelhardt9640e522007-09-10 11:50:46 +0000269 .name = "u32",
Jan Engelhardt23545c22008-02-14 04:23:04 +0100270 .family = AF_UNSPEC,
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200271 .version = XTABLES_VERSION,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000272 .size = XT_ALIGN(sizeof(struct xt_u32)),
273 .userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
274 .help = u32_help,
275 .parse = u32_parse,
Jan Engelhardt9640e522007-09-10 11:50:46 +0000276 .print = u32_print,
277 .save = u32_save,
278 .extra_opts = u32_opts,
279};
280
281void _init(void)
282{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000283 xtables_register_match(&u32_match);
Jan Engelhardt9640e522007-09-10 11:50:46 +0000284}