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
16 #include <linux/netfilter_ipv4/ipt_u32.h>
20 /* Function which prints out usage message. */
24 printf( "u32 v%s options:\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"
34 /* defined in /usr/include/getopt.h maybe in man getopt */
35 static struct option opts[] = {
40 /* Initialize the match. */
42 init(struct ipt_entry_match *m, unsigned int *nfcache)
44 *nfcache |= NFC_UNKNOWN;
47 /* shared printing code */
48 static void print_u32(struct ipt_u32 *data)
52 for (testind=0; testind < data->ntests; testind++) {
53 if (testind) printf("&&");
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;
65 printf("0x%x", data->tests[testind].location[i].number);
68 for (i = 0; i < data->tests[testind].nvalues; i++) {
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);
81 /* string_to_number is not quite what we need here ... */
82 u_int32_t parse_number(char **s, int pos)
88 number = strtol(*s, &end, 0);
90 exit_error(PARAMETER_PROBLEM,
91 "u32: at char %d expected number", pos);
93 exit_error(PARAMETER_PROBLEM,
94 "u32: at char %d error reading number", pos);
99 /* Function which parses command options; returns true if it ate an option */
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)
106 struct ipt_u32 *data = (struct ipt_u32 *)(*match)->data;
107 char *arg = argv[optind-1]; /* the argument string */
109 int state=0, testind=0, locind=0, valind=0;
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 */
118 exit_error(PARAMETER_PROBLEM,
119 "u32: input ended in location spec");
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;
126 data->ntests=testind;
127 if (testind > U32MAXSIZE)
128 exit_error(PARAMETER_PROBLEM,
129 "u32: at char %d too many &&'s",
132 print_u32(data);printf("\n");
133 exit_error(PARAMETER_PROBLEM, "debugging output done"); */
137 /* reading location: read a number if nothing read yet,
138 otherwise either op number or = to end location spec */
141 exit_error(PARAMETER_PROBLEM,
142 "u32: at char %d location spec missing", arg-start);
149 if (locind) { /* need op before number */
151 data->tests[testind].location[locind].nextop = IPT_U32_AND;
153 else 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;
160 else 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;
167 else if (*arg == '@') {
168 data->tests[testind].location[locind].nextop = IPT_U32_AT;
170 else exit_error(PARAMETER_PROBLEM,
171 "u32: at char %d operator expected", arg-start);
174 /* now a number; string_to_number skips white space? */
175 data->tests[testind].location[locind].number =
176 parse_number(&arg, arg-start);
178 if (locind > U32MAXSIZE)
179 exit_error(PARAMETER_PROBLEM,
180 "u32: at char %d too many operators", arg-start);
184 /* state 1 - reading values: read a range if nothing read yet,
185 otherwise either ,range or && to end test spec */
189 exit_error(PARAMETER_PROBLEM,
190 "u32: at char %d a second & expected", arg-start);
192 exit_error(PARAMETER_PROBLEM,
193 "u32: at char %d value spec missing", arg-start);
195 data->tests[testind].nnums = locind;
196 data->tests[testind].nvalues = valind;
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;
204 else { /* read value range */
205 if (valind) { /* need , before number */
207 exit_error(PARAMETER_PROBLEM,
208 "u32: at char %d expected , or &&", arg-start);
211 data->tests[testind].value[valind].min = parse_number(&arg, arg-start);
212 while (isspace(*arg))
213 arg++; /* another place white space could be */
216 data->tests[testind].value[valind].max
217 = parse_number(&arg, arg-start);
219 else data->tests[testind].value[valind].max
220 = data->tests[testind].value[valind].min;
222 if (valind > U32MAXSIZE)
223 exit_error(PARAMETER_PROBLEM,
224 "u32: at char %d too many ,'s", arg-start);
230 /* Final check; must specify something. */
232 final_check(unsigned int flags)
236 /* Prints out the matchinfo. */
238 print(const struct ipt_ip *ip,
239 const struct ipt_entry_match *match,
243 print_u32((struct ipt_u32 *)match->data);
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)
250 print_u32((struct ipt_u32 *)match->data);
253 struct iptables_match u32
257 IPT_ALIGN(sizeof(struct ipt_u32)),
258 IPT_ALIGN(sizeof(struct ipt_u32)),
271 register_match(&u32);