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 /* shared printing code */
41 static void print_u32(struct ipt_u32
*data
)
45 for (testind
=0; testind
< data
->ntests
; testind
++) {
46 if (testind
) printf("&&");
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
);
61 for (i
= 0; i
< data
->tests
[testind
].nvalues
; i
++) {
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
);
74 /* string_to_number is not quite what we need here ... */
75 u_int32_t
parse_number(char **s
, int pos
)
81 number
= strtoul(*s
, &end
, 0);
83 exit_error(PARAMETER_PROBLEM
,
84 "u32: at char %d expected number", pos
);
86 exit_error(PARAMETER_PROBLEM
,
87 "u32: at char %d error reading number", pos
);
92 /* Function which parses command options; returns true if it ate an option */
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 */
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 */
111 exit_error(PARAMETER_PROBLEM
,
112 "u32: input ended in location spec");
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
;
119 data
->ntests
=testind
;
120 if (testind
> U32MAXSIZE
)
121 exit_error(PARAMETER_PROBLEM
,
122 "u32: at char %d too many &&'s",
125 print_u32(data);printf("\n");
126 exit_error(PARAMETER_PROBLEM, "debugging output done"); */
130 /* reading location: read a number if nothing read yet,
131 otherwise either op number or = to end location spec */
134 exit_error(PARAMETER_PROBLEM
,
135 "u32: at char %d location spec missing", arg
-start
);
142 if (locind
) { /* need op before number */
144 data
->tests
[testind
].location
[locind
].nextop
= IPT_U32_AND
;
146 else 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
== '>') {
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
);
167 /* now a number; string_to_number skips white space? */
168 data
->tests
[testind
].location
[locind
].number
=
169 parse_number(&arg
, arg
-start
);
171 if (locind
> U32MAXSIZE
)
172 exit_error(PARAMETER_PROBLEM
,
173 "u32: at char %d too many operators", arg
-start
);
177 /* state 1 - reading values: read a range if nothing read yet,
178 otherwise either ,range or && to end test spec */
182 exit_error(PARAMETER_PROBLEM
,
183 "u32: at char %d a second & expected", arg
-start
);
185 exit_error(PARAMETER_PROBLEM
,
186 "u32: at char %d value spec missing", arg
-start
);
188 data
->tests
[testind
].nnums
= locind
;
189 data
->tests
[testind
].nvalues
= valind
;
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 */
200 exit_error(PARAMETER_PROBLEM
,
201 "u32: at char %d expected , or &&", arg
-start
);
204 data
->tests
[testind
].value
[valind
].min
= parse_number(&arg
, arg
-start
);
205 while (isspace(*arg
))
206 arg
++; /* another place white space could be */
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
;
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. */
225 final_check(unsigned int flags
)
229 /* Prints out the matchinfo. */
231 print(const struct ipt_ip
*ip
,
232 const struct ipt_entry_match
*match
,
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
)
243 print_u32((struct ipt_u32
*)match
->data
);
246 struct iptables_match u32
= {
249 .version
= IPTABLES_VERSION
,
250 .size
= IPT_ALIGN(sizeof(struct ipt_u32
)),
251 .userspacesize
= IPT_ALIGN(sizeof(struct ipt_u32
)),
254 .final_check
= &final_check
,
263 register_match(&u32
);