NETFILTER: remove unnecessary goto statement for error recovery
[tomato.git] / release / src-rt / linux / linux-2.6 / net / ipv4 / netfilter / ipt_u32.c
blob5077707a805c4e82243ab7ac4378aa086bbd5263
1 /*
2 * ipt_u32 - kernel module to match u32 packet content
4 * Original author: Don Cohen <don@isis.cs3-inc.com>
5 * © Jan Engelhardt <jengelh@gmx.de>, 2007
6 */
8 /*
9 U32 tests whether quantities of up to 4 bytes extracted from a packet
10 have specified values. The specification of what to extract is general
11 enough to find data at given offsets from tcp headers or payloads.
13 --u32 tests
14 The argument amounts to a program in a small language described below.
15 tests := location = value | tests && location = value
16 value := range | value , range
17 range := number | number : number
18 a single number, n, is interpreted the same as n:n
19 n:m is interpreted as the range of numbers >=n and <=m
20 location := number | location operator number
21 operator := & | << | >> | @
23 The operators &, <<, >>, && mean the same as in c. The = is really a set
24 membership operator and the value syntax describes a set. The @ operator
25 is what allows moving to the next header and is described further below.
27 *** Until I can find out how to avoid it, there are some artificial limits
28 on the size of the tests:
29 - no more than 10 ='s (and 9 &&'s) in the u32 argument
30 - no more than 10 ranges (and 9 commas) per value
31 - no more than 10 numbers (and 9 operators) per location
33 To describe the meaning of location, imagine the following machine that
34 interprets it. There are three registers:
35 A is of type char*, initially the address of the IP header
36 B and C are unsigned 32 bit integers, initially zero
38 The instructions are:
39 number B = number;
40 C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
41 &number C = C&number
42 <<number C = C<<number
43 >>number C = C>>number
44 @number A = A+C; then do the instruction number
45 Any access of memory outside [skb->head,skb->end] causes the match to fail.
46 Otherwise the result of the computation is the final value of C.
48 Whitespace is allowed but not required in the tests.
49 However the characters that do occur there are likely to require
50 shell quoting, so it's a good idea to enclose the arguments in quotes.
52 Example:
53 match IP packets with total length >= 256
54 The IP header contains a total length field in bytes 2-3.
55 --u32 "0&0xFFFF=0x100:0xFFFF"
56 read bytes 0-3
57 AND that with FFFF (giving bytes 2-3),
58 and test whether that's in the range [0x100:0xFFFF]
60 Example: (more realistic, hence more complicated)
61 match icmp packets with icmp type 0
62 First test that it's an icmp packet, true iff byte 9 (protocol) = 1
63 --u32 "6&0xFF=1 && ...
64 read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
65 Next test that it's not a fragment.
66 (If so it might be part of such a packet but we can't always tell.)
67 n.b. This test is generally needed if you want to match anything
68 beyond the IP header.
69 The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
70 packet (not a fragment). Alternatively, you can allow first fragments
71 by only testing the last 5 bits of byte 6.
72 ... 4&0x3FFF=0 && ...
73 Last test: the first byte past the IP header (the type) is 0
74 This is where we have to use the @syntax. The length of the IP header
75 (IHL) in 32 bit words is stored in the right half of byte 0 of the
76 IP header itself.
77 ... 0>>22&0x3C@0>>24=0"
78 The first 0 means read bytes 0-3,
79 >>22 means shift that 22 bits to the right. Shifting 24 bits would give
80 the first byte, so only 22 bits is four times that plus a few more bits.
81 &3C then eliminates the two extra bits on the right and the first four
82 bits of the first byte.
83 For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
84 In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
85 >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
86 @ means to use this number as a new offset into the packet, and read
87 four bytes starting from there. This is the first 4 bytes of the icmp
88 payload, of which byte 0 is the icmp type. Therefore we simply shift
89 the value 24 to the right to throw out all but the first byte and compare
90 the result with 0.
92 Example:
93 tcp payload bytes 8-12 is any of 1, 2, 5 or 8
94 First we test that the packet is a tcp packet (similar to icmp).
95 --u32 "6&0xFF=6 && ...
96 Next, test that it's not a fragment (same as above).
97 ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
98 0>>22&3C as above computes the number of bytes in the IP header.
99 @ makes this the new offset into the packet, which is the start of the
100 tcp header. The length of the tcp header (again in 32 bit words) is
101 the left half of byte 12 of the tcp header. The 12>>26&3C
102 computes this length in bytes (similar to the IP header before).
103 @ makes this the new offset, which is the start of the tcp payload.
104 Finally 8 reads bytes 8-12 of the payload and = checks whether the
105 result is any of 1, 2, 5 or 8
108 #include <linux/module.h>
109 #include <linux/moduleparam.h>
110 #include <linux/spinlock.h>
111 #include <linux/skbuff.h>
112 #include <linux/types.h>
114 #include <linux/netfilter_ipv4/ipt_u32.h>
115 #include <linux/netfilter_ipv4/ip_tables.h>
117 MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
118 MODULE_DESCRIPTION("netfilter u32 match module");
119 MODULE_LICENSE("GPL");
120 MODULE_ALIAS("ip6t_u32");
122 static int u32_match_it(const struct ipt_u32 *data,
123 const struct sk_buff *skb)
125 const struct ipt_u32_test *ct;
126 unsigned int testind;
127 unsigned int nnums;
128 unsigned int nvals;
129 unsigned int i;
130 u_int32_t pos;
131 u_int32_t val;
132 u_int32_t at;
133 int ret;
136 * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17"
137 * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands.
139 for (testind = 0; testind < data->ntests; ++testind) {
140 ct = &data->tests[testind];
141 at = 0;
142 pos = ct->location[0].number;
144 if (skb->len < 4 || pos > skb->len - 4)
145 return 0;
147 ret = skb_copy_bits(skb, pos, &val, sizeof(val));
148 BUG_ON(ret < 0);
149 val = ntohl(val);
150 nnums = ct->nnums;
152 /* Inner loop runs over "&", "<<", ">>" and "@" operands */
153 for (i = 1; i < nnums; ++i) {
154 u_int32_t number = ct->location[i].number;
155 switch (ct->location[i].nextop) {
156 case IPT_U32_AND:
157 val &= number;
158 break;
159 case IPT_U32_LEFTSH:
160 val <<= number;
161 break;
162 case IPT_U32_RIGHTSH:
163 val >>= number;
164 break;
165 case IPT_U32_AT:
166 if (at + val < at)
167 return 0;
168 at += val;
169 pos = number;
170 if (at + 4 < at || skb->len < at + 4 ||
171 pos > skb->len - at - 4)
172 return 0;
174 ret = skb_copy_bits(skb, at + pos, &val,
175 sizeof(val));
176 BUG_ON(ret < 0);
177 val = ntohl(val);
178 break;
182 /* Run over the "," and ":" operands */
183 nvals = ct->nvalues;
184 for (i = 0; i < nvals; ++i)
185 if (ct->value[i].min <= val && val <= ct->value[i].max)
186 break;
188 if (i >= ct->nvalues)
189 return 0;
192 return 1;
195 static int
196 match(const struct sk_buff *skb,
197 const struct net_device *in,
198 const struct net_device *out,
199 const struct xt_match *match,
200 const void *matchinfo,
201 int offset,
202 unsigned int protoff,
203 int *hotdrop)
205 const struct ipt_u32 *data = matchinfo;
206 int ret;
208 ret = u32_match_it(data, skb);
209 return ret ^ data->invert;
212 static int
213 checkentry(const char *tablename,
214 const void *ip,
215 const struct xt_match *match,
216 void *matchinfo,
217 unsigned int hook_mask)
219 return 1;
222 static struct xt_match u32_reg[] = {
224 .name = "u32",
225 .family = AF_INET,
226 .match = &match,
227 .matchsize = sizeof(struct ipt_u32),
228 .checkentry = &checkentry,
229 .me = THIS_MODULE
232 .name = "u32",
233 .family = AF_INET6,
234 .match = &match,
235 .matchsize = sizeof(struct ipt_u32),
236 .checkentry = &checkentry,
237 .me = THIS_MODULE
241 static int __init init(void)
243 return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
246 static void __exit fini(void)
248 xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
251 module_init(init);
252 module_exit(fini);