tizen 2.3.1 release
[external/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 <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
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
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 ... */
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
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
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
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
276 void _init(void)
277 {
278         xtables_register_match(&u32_match);
279 }