Git init
[profile/ivi/iptables.git] / extensions / libxt_u32.c
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 <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #include <xtables.h>
23 #include <linux/netfilter/xt_u32.h>
24
25 static const struct option u32_opts[] = {
26         {"u32", 1, NULL, 'u'},
27         { .name = NULL }
28 };
29
30 static 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
42 static 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 ... */
87 static 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                 xtables_error(PARAMETER_PROBLEM,
96                            "u32: at char %d: expected number", pos);
97         if (errno != 0)
98                 xtables_error(PARAMETER_PROBLEM,
99                            "u32: at char %d: error reading number", pos);
100         *s = end;
101         return number;
102 }
103
104 static 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 = optarg; /* 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                                 xtables_error(PARAMETER_PROBLEM,
133                                            "u32: abrupt end of input after location specifier");
134                         if (valind == 0)
135                                 xtables_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                                 xtables_error(PARAMETER_PROBLEM,
144                                            "u32: at char %u: too many \"&&\"s",
145                                            (unsigned int)(arg - start));
146                         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                                         xtables_error(PARAMETER_PROBLEM,
157                                                    "u32: at char %u: "
158                                                    "location spec missing",
159                                                    (unsigned int)(arg - start));
160                                 } 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                                                         xtables_error(PARAMETER_PROBLEM,
172                                                                    "u32: at char %u: a second '<' was expected", (unsigned int)(arg - start));
173                                                 ct->location[locind].nextop = XT_U32_LEFTSH;
174                                         } else if (*arg == '>') {
175                                                 if (*++arg != '>')
176                                                         xtables_error(PARAMETER_PROBLEM,
177                                                                    "u32: at char %u: a second '>' was expected", (unsigned int)(arg - start));
178                                                 ct->location[locind].nextop = XT_U32_RIGHTSH;
179                                         } else if (*arg == '@') {
180                                                 ct->location[locind].nextop = XT_U32_AT;
181                                         } else {
182                                                 xtables_error(PARAMETER_PROBLEM,
183                                                         "u32: at char %u: operator expected", (unsigned int)(arg - start));
184                                         }
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                                         xtables_error(PARAMETER_PROBLEM,
192                                                    "u32: at char %u: too many operators", (unsigned int)(arg - start));
193                         }
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                                         xtables_error(PARAMETER_PROBLEM,
203                                                    "u32: at char %u: a second '&' was expected", (unsigned int)(arg - start));
204                                 if (valind == 0) {
205                                         xtables_error(PARAMETER_PROBLEM,
206                                                    "u32: at char %u: value spec missing", (unsigned int)(arg - start));
207                                 } else {
208                                         ct->nnums   = locind;
209                                         ct->nvalues = valind;
210                                         ct = &data->tests[++testind];
211                                         if (testind > XT_U32_MAXSIZE)
212                                                 xtables_error(PARAMETER_PROBLEM,
213                                                            "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start));
214                                         ++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                                                 xtables_error(PARAMETER_PROBLEM,
223                                                            "u32: at char %u: expected \",\" or \"&&\"", (unsigned int)(arg - start));
224                                         ++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                                         xtables_error(PARAMETER_PROBLEM,
243                                                    "u32: at char %u: too many \",\"s", (unsigned int)(arg - start));
244                         }
245                 }
246         }
247 }
248
249 static 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);
257 }
258
259 static 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);
266 }
267
268 static struct xtables_match u32_match = {
269         .name          = "u32",
270         .family        = NFPROTO_UNSPEC,
271         .version       = XTABLES_VERSION,
272         .size          = XT_ALIGN(sizeof(struct xt_u32)),
273         .userspacesize = XT_ALIGN(sizeof(struct xt_u32)),
274         .help          = u32_help,
275         .parse         = u32_parse,
276         .print         = u32_print,
277         .save          = u32_save,
278         .extra_opts    = u32_opts,
279 };
280
281 void _init(void)
282 {
283         xtables_register_match(&u32_match);
284 }