iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_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/ipv4/netfilter/ipt_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 #include <stdio.h>
11 #include <netdb.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <getopt.h>
15 #include <iptables.h>
16 #include <linux/netfilter_ipv4/ipt_u32.h>
17 #include <errno.h>
18 #include <ctype.h>
19
20 /* Function which prints out usage message. */
21 static void
22 help(void)
23 {
24         printf( "u32 v%s options:\n"
25                 " --u32 tests\n"
26                 " tests := location = value | tests && location = value\n"
27                 " value := range | value , range\n"
28                 " range := number | number : number\n"
29                 " location := number | location operator number\n"
30                 " operator := & | << | >> | @\n"
31                 ,IPTABLES_VERSION);
32 }
33
34 /* defined in /usr/include/getopt.h maybe in man getopt */
35 static struct option opts[] = {
36         { "u32", 1, 0, '1' },
37         { 0 }
38 };
39
40 /* Initialize the match. */
41 static void
42 init(struct ipt_entry_match *m, unsigned int *nfcache)
43 {
44         *nfcache |= NFC_UNKNOWN;
45 }
46
47 /* shared printing code */
48 static void print_u32(struct ipt_u32 *data)
49 {
50         unsigned int testind;
51
52         for (testind=0; testind < data->ntests; testind++) {
53                 if (testind) printf("&&");
54                 {
55                         unsigned int i;
56
57                         printf("0x%x", data->tests[testind].location[0].number);
58                         for (i = 1; i < data->tests[testind].nnums; i++) {
59                                 switch (data->tests[testind].location[i].nextop) {
60                                 case IPT_U32_AND: printf("&"); break;
61                                 case IPT_U32_LEFTSH: printf("<<"); break;
62                                 case IPT_U32_RIGHTSH: printf(">>"); break;
63                                 case IPT_U32_AT: printf("@"); break;
64                                 }
65                                 printf("0x%x", data->tests[testind].location[i].number);
66                         }
67                         printf("=");
68                         for (i = 0; i < data->tests[testind].nvalues; i++) {
69                                 if (i) printf(",");
70                                 if (data->tests[testind].value[i].min
71                                     == data->tests[testind].value[i].max)
72                                         printf("0x%x", data->tests[testind].value[i].min);
73                                 else printf("0x%x:0x%x", data->tests[testind].value[i].min,
74                                             data->tests[testind].value[i].max);
75                         }
76                 }
77         }
78         printf(" ");
79 }
80
81 /* string_to_number is not quite what we need here ... */
82 u_int32_t parse_number(char **s, int pos)
83 {
84         u_int32_t number;
85         char *end;
86         errno = 0;
87
88         number = strtol(*s, &end, 0);
89         if (end == *s)
90                 exit_error(PARAMETER_PROBLEM, 
91                            "u32: at char %d expected number", pos);
92         if (errno)
93                 exit_error(PARAMETER_PROBLEM, 
94                            "u32: at char %d error reading number", pos);
95         *s = end;
96         return number;
97 }
98
99 /* Function which parses command options; returns true if it ate an option */
100 static int
101 parse(int c, char **argv, int invert, unsigned int *flags,
102       const struct ipt_entry *entry,
103       unsigned int *nfcache,
104       struct ipt_entry_match **match)
105 {
106         struct ipt_u32 *data = (struct ipt_u32 *)(*match)->data;
107         char *arg = argv[optind-1]; /* the argument string */
108         char *start = arg;
109         int state=0, testind=0, locind=0, valind=0;
110
111         if (c != '1') return 0;
112         /* states: 0 = looking for numbers and operations, 1 = looking for ranges */
113         while (1) { /* read next operand/number or range */
114                 while (isspace(*arg)) 
115                         arg++;  /* skip white space */
116                 if (! *arg) { /* end of argument found */
117                         if (state == 0)
118                                 exit_error(PARAMETER_PROBLEM, 
119                                            "u32: input ended in location spec");
120                         if (valind == 0)
121                                 exit_error(PARAMETER_PROBLEM, 
122                                            "u32: test ended with no value spec");
123                         data->tests[testind].nnums = locind;
124                         data->tests[testind].nvalues = valind;
125                         testind++;
126                         data->ntests=testind;
127                         if (testind > U32MAXSIZE)
128                                 exit_error(PARAMETER_PROBLEM, 
129                                            "u32: at char %d too many &&'s",
130                                            arg-start);
131                         /* debugging 
132                            print_u32(data);printf("\n");
133                            exit_error(PARAMETER_PROBLEM, "debugging output done"); */
134                         return 1;
135                 }
136                 if (state == 0) {
137                         /* reading location: read a number if nothing read yet,
138                            otherwise either op number or = to end location spec */       
139                         if (*arg == '=') {
140                                 if (locind == 0)
141                                         exit_error(PARAMETER_PROBLEM,
142                                                    "u32: at char %d location spec missing", arg-start);
143                                 else {
144                                         arg++; 
145                                         state=1;
146                                 }
147                         }
148                         else {
149                                 if (locind) { /* need op before number */
150                                         if (*arg == '&') {
151                                                 data->tests[testind].location[locind].nextop = IPT_U32_AND;
152                                         }
153                                         else if (*arg == '<') {
154                                                 arg++;
155                                                 if (*arg != '<')
156                                                         exit_error(PARAMETER_PROBLEM,
157                                                                    "u32: at char %d a second < expected", arg-start);
158                                                 data->tests[testind].location[locind].nextop = IPT_U32_LEFTSH;
159                                         }
160                                         else if (*arg == '>') {
161                                                 arg++;
162                                                 if (*arg != '>')
163                                                         exit_error(PARAMETER_PROBLEM,
164                                                                    "u32: at char %d a second > expected", arg-start);
165                                                 data->tests[testind].location[locind].nextop = IPT_U32_RIGHTSH;
166                                         }
167                                         else if (*arg == '@') {
168                                                 data->tests[testind].location[locind].nextop = IPT_U32_AT;
169                                         }
170                                         else exit_error(PARAMETER_PROBLEM,
171                                                         "u32: at char %d operator expected", arg-start);
172                                         arg++;
173                                 }
174                                 /* now a number; string_to_number skips white space? */
175                                 data->tests[testind].location[locind].number =
176                                         parse_number(&arg, arg-start);
177                                 locind++;
178                                 if (locind > U32MAXSIZE)
179                                         exit_error(PARAMETER_PROBLEM,
180                                                    "u32: at char %d too many operators", arg-start);
181                         }
182                 }
183                 else {
184                         /* state 1 - reading values: read a range if nothing read yet,
185                            otherwise either ,range or && to end test spec */
186                         if (*arg == '&') {
187                                 arg++;
188                                 if (*arg != '&')
189                                         exit_error(PARAMETER_PROBLEM,
190                                                    "u32: at char %d a second & expected", arg-start);
191                                 if (valind == 0)
192                                         exit_error(PARAMETER_PROBLEM,
193                                                    "u32: at char %d value spec missing", arg-start);
194                                 else {
195                                         data->tests[testind].nnums = locind;
196                                         data->tests[testind].nvalues = valind;
197                                         testind++;
198                                         if (testind > U32MAXSIZE)
199                                                 exit_error(PARAMETER_PROBLEM,
200                                                            "u32: at char %d too many &&'s", arg-start);
201                                         arg++; state=0; locind=0; valind=0;
202                                 }
203                         }
204                         else { /* read value range */
205                                 if (valind) { /* need , before number */
206                                         if (*arg != ',')
207                                                 exit_error(PARAMETER_PROBLEM,
208                                                            "u32: at char %d expected , or &&", arg-start);
209                                         arg++;
210                                 }
211                                 data->tests[testind].value[valind].min = parse_number(&arg, arg-start);
212                                 while (isspace(*arg)) 
213                                         arg++;  /* another place white space could be */
214                                 if (*arg==':') {
215                                         arg++;
216                                         data->tests[testind].value[valind].max
217                                                 = parse_number(&arg, arg-start);
218                                 }
219                                 else data->tests[testind].value[valind].max
220                                              = data->tests[testind].value[valind].min;
221                                 valind++;
222                                 if (valind > U32MAXSIZE)
223                                         exit_error(PARAMETER_PROBLEM,
224                                                    "u32: at char %d too many ,'s", arg-start);
225                         }
226                 }
227         }
228 }
229
230 /* Final check; must specify something. */
231 static void
232 final_check(unsigned int flags)
233 {
234 }
235
236 /* Prints out the matchinfo. */
237 static void
238 print(const struct ipt_ip *ip,
239       const struct ipt_entry_match *match,
240       int numeric)
241 {
242         printf("u32 ");
243         print_u32((struct ipt_u32 *)match->data);
244 }
245
246 /* Saves the union ipt_matchinfo in parsable form to stdout. */
247 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
248 {
249         printf("--u32 ");
250         print_u32((struct ipt_u32 *)match->data);
251 }
252
253 struct iptables_match u32
254 = { NULL,
255     "u32",
256     IPTABLES_VERSION,
257     IPT_ALIGN(sizeof(struct ipt_u32)),
258     IPT_ALIGN(sizeof(struct ipt_u32)),
259     &help,
260     &init,
261     &parse,
262     &final_check,
263     &print,
264     &save,
265     opts
266 };
267
268 void
269 _init(void)
270 {
271         register_match(&u32);
272 }