Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / extensions / libipt_u32.c
blob7504510038212aea96adb3ea54111660fc3ba971
1 /* Shared library add-on to iptables to add u32 matching,
2 * generalized matching on values found at packet offsets
4 * Detailed doc is in the kernel module source
5 * net/ipv4/netfilter/ipt_u32.c
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>
20 /* Function which prints out usage message. */
21 static void
22 help(void)
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);
34 /* defined in /usr/include/getopt.h maybe in man getopt */
35 static struct option opts[] = {
36 { "u32", 1, 0, '1' },
37 { 0 }
40 /* shared printing code */
41 static void print_u32(struct ipt_u32 *data)
43 unsigned int testind;
45 for (testind=0; testind < data->ntests; testind++) {
46 if (testind) printf("&&");
48 unsigned int i;
50 printf("0x%x", data->tests[testind].location[0].number);
51 for (i = 1; i < data->tests[testind].nnums; i++) {
52 switch (data->tests[testind].location[i].nextop) {
53 case IPT_U32_AND: printf("&"); break;
54 case IPT_U32_LEFTSH: printf("<<"); break;
55 case IPT_U32_RIGHTSH: printf(">>"); break;
56 case IPT_U32_AT: printf("@"); break;
58 printf("0x%x", data->tests[testind].location[i].number);
60 printf("=");
61 for (i = 0; i < data->tests[testind].nvalues; i++) {
62 if (i) printf(",");
63 if (data->tests[testind].value[i].min
64 == data->tests[testind].value[i].max)
65 printf("0x%x", data->tests[testind].value[i].min);
66 else printf("0x%x:0x%x", data->tests[testind].value[i].min,
67 data->tests[testind].value[i].max);
71 printf(" ");
74 /* string_to_number is not quite what we need here ... */
75 u_int32_t parse_number(char **s, int pos)
77 u_int32_t number;
78 char *end;
79 errno = 0;
81 number = strtoul(*s, &end, 0);
82 if (end == *s)
83 exit_error(PARAMETER_PROBLEM,
84 "u32: at char %d expected number", pos);
85 if (errno)
86 exit_error(PARAMETER_PROBLEM,
87 "u32: at char %d error reading number", pos);
88 *s = end;
89 return number;
92 /* Function which parses command options; returns true if it ate an option */
93 static int
94 parse(int c, char **argv, int invert, unsigned int *flags,
95 const struct ipt_entry *entry,
96 unsigned int *nfcache,
97 struct ipt_entry_match **match)
99 struct ipt_u32 *data = (struct ipt_u32 *)(*match)->data;
100 char *arg = argv[optind-1]; /* the argument string */
101 char *start = arg;
102 int state=0, testind=0, locind=0, valind=0;
104 if (c != '1') return 0;
105 /* states: 0 = looking for numbers and operations, 1 = looking for ranges */
106 while (1) { /* read next operand/number or range */
107 while (isspace(*arg))
108 arg++; /* skip white space */
109 if (! *arg) { /* end of argument found */
110 if (state == 0)
111 exit_error(PARAMETER_PROBLEM,
112 "u32: input ended in location spec");
113 if (valind == 0)
114 exit_error(PARAMETER_PROBLEM,
115 "u32: test ended with no value spec");
116 data->tests[testind].nnums = locind;
117 data->tests[testind].nvalues = valind;
118 testind++;
119 data->ntests=testind;
120 if (testind > U32MAXSIZE)
121 exit_error(PARAMETER_PROBLEM,
122 "u32: at char %d too many &&'s",
123 arg-start);
124 /* debugging
125 print_u32(data);printf("\n");
126 exit_error(PARAMETER_PROBLEM, "debugging output done"); */
127 return 1;
129 if (state == 0) {
130 /* reading location: read a number if nothing read yet,
131 otherwise either op number or = to end location spec */
132 if (*arg == '=') {
133 if (locind == 0)
134 exit_error(PARAMETER_PROBLEM,
135 "u32: at char %d location spec missing", arg-start);
136 else {
137 arg++;
138 state=1;
141 else {
142 if (locind) { /* need op before number */
143 if (*arg == '&') {
144 data->tests[testind].location[locind].nextop = IPT_U32_AND;
146 else if (*arg == '<') {
147 arg++;
148 if (*arg != '<')
149 exit_error(PARAMETER_PROBLEM,
150 "u32: at char %d a second < expected", arg-start);
151 data->tests[testind].location[locind].nextop = IPT_U32_LEFTSH;
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_RIGHTSH;
160 else if (*arg == '@') {
161 data->tests[testind].location[locind].nextop = IPT_U32_AT;
163 else exit_error(PARAMETER_PROBLEM,
164 "u32: at char %d operator expected", arg-start);
165 arg++;
167 /* now a number; string_to_number skips white space? */
168 data->tests[testind].location[locind].number =
169 parse_number(&arg, arg-start);
170 locind++;
171 if (locind > U32MAXSIZE)
172 exit_error(PARAMETER_PROBLEM,
173 "u32: at char %d too many operators", arg-start);
176 else {
177 /* state 1 - reading values: read a range if nothing read yet,
178 otherwise either ,range or && to end test spec */
179 if (*arg == '&') {
180 arg++;
181 if (*arg != '&')
182 exit_error(PARAMETER_PROBLEM,
183 "u32: at char %d a second & expected", arg-start);
184 if (valind == 0)
185 exit_error(PARAMETER_PROBLEM,
186 "u32: at char %d value spec missing", arg-start);
187 else {
188 data->tests[testind].nnums = locind;
189 data->tests[testind].nvalues = valind;
190 testind++;
191 if (testind > U32MAXSIZE)
192 exit_error(PARAMETER_PROBLEM,
193 "u32: at char %d too many &&'s", arg-start);
194 arg++; state=0; locind=0; valind=0;
197 else { /* read value range */
198 if (valind) { /* need , before number */
199 if (*arg != ',')
200 exit_error(PARAMETER_PROBLEM,
201 "u32: at char %d expected , or &&", arg-start);
202 arg++;
204 data->tests[testind].value[valind].min = parse_number(&arg, arg-start);
205 while (isspace(*arg))
206 arg++; /* another place white space could be */
207 if (*arg==':') {
208 arg++;
209 data->tests[testind].value[valind].max
210 = parse_number(&arg, arg-start);
212 else data->tests[testind].value[valind].max
213 = data->tests[testind].value[valind].min;
214 valind++;
215 if (valind > U32MAXSIZE)
216 exit_error(PARAMETER_PROBLEM,
217 "u32: at char %d too many ,'s", arg-start);
223 /* Final check; must specify something. */
224 static void
225 final_check(unsigned int flags)
229 /* Prints out the matchinfo. */
230 static void
231 print(const struct ipt_ip *ip,
232 const struct ipt_entry_match *match,
233 int numeric)
235 printf("u32 ");
236 print_u32((struct ipt_u32 *)match->data);
239 /* Saves the union ipt_matchinfo in parsable form to stdout. */
240 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
242 printf("--u32 ");
243 print_u32((struct ipt_u32 *)match->data);
246 struct iptables_match u32 = {
247 .next = NULL,
248 .name = "u32",
249 .version = IPTABLES_VERSION,
250 .size = IPT_ALIGN(sizeof(struct ipt_u32)),
251 .userspacesize = IPT_ALIGN(sizeof(struct ipt_u32)),
252 .help = &help,
253 .parse = &parse,
254 .final_check = &final_check,
255 .print = &print,
256 .save = &save,
257 .extra_opts = opts
260 void
261 _init(void)
263 register_match(&u32);