]>
Commit | Line | Data |
---|---|---|
7f651772 | 1 | diff -Nru linux-2.6.22/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.22-pom2patch/include/linux/netfilter_ipv4/ipt_u32.h |
2 | --- linux-2.6.22/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ linux-2.6.22-pom2patch/include/linux/netfilter_ipv4/ipt_u32.h 2007-08-07 18:40:11.000000000 +0200 | |
4 | @@ -0,0 +1,40 @@ | |
5 | +#ifndef _IPT_U32_H | |
6 | +#define _IPT_U32_H | |
7 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
8 | + | |
9 | +enum ipt_u32_ops | |
10 | +{ | |
11 | + IPT_U32_AND, | |
12 | + IPT_U32_LEFTSH, | |
13 | + IPT_U32_RIGHTSH, | |
14 | + IPT_U32_AT | |
15 | +}; | |
16 | + | |
17 | +struct ipt_u32_location_element | |
18 | +{ | |
19 | + u_int32_t number; | |
20 | + u_int8_t nextop; | |
21 | +}; | |
22 | +struct ipt_u32_value_element | |
23 | +{ | |
24 | + u_int32_t min; | |
25 | + u_int32_t max; | |
26 | +}; | |
27 | +/* *** any way to allow for an arbitrary number of elements? | |
28 | + for now I settle for a limit of 10 of each */ | |
29 | +#define U32MAXSIZE 10 | |
30 | +struct ipt_u32_test | |
31 | +{ | |
32 | + u_int8_t nnums; | |
33 | + struct ipt_u32_location_element location[U32MAXSIZE+1]; | |
34 | + u_int8_t nvalues; | |
35 | + struct ipt_u32_value_element value[U32MAXSIZE+1]; | |
36 | +}; | |
37 | + | |
38 | +struct ipt_u32 | |
39 | +{ | |
40 | + u_int8_t ntests; | |
41 | + struct ipt_u32_test tests[U32MAXSIZE+1]; | |
42 | +}; | |
43 | + | |
44 | +#endif /*_IPT_U32_H*/ | |
45 | diff -Nru linux-2.6.22/net/ipv4/netfilter/ipt_u32.c linux-2.6.22-pom2patch/net/ipv4/netfilter/ipt_u32.c | |
46 | --- linux-2.6.22/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100 | |
47 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/ipt_u32.c 2007-08-07 18:40:11.000000000 +0200 | |
48 | @@ -0,0 +1,237 @@ | |
49 | +/* Kernel module to match u32 packet content. */ | |
50 | + | |
51 | +/* | |
52 | +U32 tests whether quantities of up to 4 bytes extracted from a packet | |
53 | +have specified values. The specification of what to extract is general | |
54 | +enough to find data at given offsets from tcp headers or payloads. | |
55 | + | |
56 | + --u32 tests | |
57 | + The argument amounts to a program in a small language described below. | |
58 | + tests := location = value | tests && location = value | |
59 | + value := range | value , range | |
60 | + range := number | number : number | |
61 | + a single number, n, is interpreted the same as n:n | |
62 | + n:m is interpreted as the range of numbers >=n and <=m | |
63 | + location := number | location operator number | |
64 | + operator := & | << | >> | @ | |
65 | + | |
66 | + The operators &, <<, >>, && mean the same as in c. The = is really a set | |
67 | + membership operator and the value syntax describes a set. The @ operator | |
68 | + is what allows moving to the next header and is described further below. | |
69 | + | |
70 | + *** Until I can find out how to avoid it, there are some artificial limits | |
71 | + on the size of the tests: | |
72 | + - no more than 10 ='s (and 9 &&'s) in the u32 argument | |
73 | + - no more than 10 ranges (and 9 commas) per value | |
74 | + - no more than 10 numbers (and 9 operators) per location | |
75 | + | |
76 | + To describe the meaning of location, imagine the following machine that | |
77 | + interprets it. There are three registers: | |
78 | + A is of type char*, initially the address of the IP header | |
79 | + B and C are unsigned 32 bit integers, initially zero | |
80 | + | |
81 | + The instructions are: | |
82 | + number B = number; | |
83 | + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3) | |
84 | + &number C = C&number | |
85 | + <<number C = C<<number | |
86 | + >>number C = C>>number | |
87 | + @number A = A+C; then do the instruction number | |
88 | + Any access of memory outside [skb->head,skb->end] causes the match to fail. | |
89 | + Otherwise the result of the computation is the final value of C. | |
90 | + | |
91 | + Whitespace is allowed but not required in the tests. | |
92 | + However the characters that do occur there are likely to require | |
93 | + shell quoting, so it's a good idea to enclose the arguments in quotes. | |
94 | + | |
95 | +Example: | |
96 | + match IP packets with total length >= 256 | |
97 | + The IP header contains a total length field in bytes 2-3. | |
98 | + --u32 "0&0xFFFF=0x100:0xFFFF" | |
99 | + read bytes 0-3 | |
100 | + AND that with FFFF (giving bytes 2-3), | |
101 | + and test whether that's in the range [0x100:0xFFFF] | |
102 | + | |
103 | +Example: (more realistic, hence more complicated) | |
104 | + match icmp packets with icmp type 0 | |
105 | + First test that it's an icmp packet, true iff byte 9 (protocol) = 1 | |
106 | + --u32 "6&0xFF=1 && ... | |
107 | + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1 | |
108 | + Next test that it's not a fragment. | |
109 | + (If so it might be part of such a packet but we can't always tell.) | |
110 | + n.b. This test is generally needed if you want to match anything | |
111 | + beyond the IP header. | |
112 | + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete | |
113 | + packet (not a fragment). Alternatively, you can allow first fragments | |
114 | + by only testing the last 5 bits of byte 6. | |
115 | + ... 4&0x3FFF=0 && ... | |
116 | + Last test: the first byte past the IP header (the type) is 0 | |
117 | + This is where we have to use the @syntax. The length of the IP header | |
118 | + (IHL) in 32 bit words is stored in the right half of byte 0 of the | |
119 | + IP header itself. | |
120 | + ... 0>>22&0x3C@0>>24=0" | |
121 | + The first 0 means read bytes 0-3, | |
122 | + >>22 means shift that 22 bits to the right. Shifting 24 bits would give | |
123 | + the first byte, so only 22 bits is four times that plus a few more bits. | |
124 | + &3C then eliminates the two extra bits on the right and the first four | |
125 | + bits of the first byte. | |
126 | + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long. | |
127 | + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, | |
128 | + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100. | |
129 | + @ means to use this number as a new offset into the packet, and read | |
130 | + four bytes starting from there. This is the first 4 bytes of the icmp | |
131 | + payload, of which byte 0 is the icmp type. Therefore we simply shift | |
132 | + the value 24 to the right to throw out all but the first byte and compare | |
133 | + the result with 0. | |
134 | + | |
135 | +Example: | |
136 | + tcp payload bytes 8-12 is any of 1, 2, 5 or 8 | |
137 | + First we test that the packet is a tcp packet (similar to icmp). | |
138 | + --u32 "6&0xFF=6 && ... | |
139 | + Next, test that it's not a fragment (same as above). | |
140 | + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8" | |
141 | + 0>>22&3C as above computes the number of bytes in the IP header. | |
142 | + @ makes this the new offset into the packet, which is the start of the | |
143 | + tcp header. The length of the tcp header (again in 32 bit words) is | |
144 | + the left half of byte 12 of the tcp header. The 12>>26&3C | |
145 | + computes this length in bytes (similar to the IP header before). | |
146 | + @ makes this the new offset, which is the start of the tcp payload. | |
147 | + Finally 8 reads bytes 8-12 of the payload and = checks whether the | |
148 | + result is any of 1, 2, 5 or 8 | |
149 | +*/ | |
150 | + | |
151 | +#include <linux/module.h> | |
152 | +#include <linux/skbuff.h> | |
153 | + | |
154 | +#include <linux/netfilter_ipv4/ipt_u32.h> | |
155 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
156 | + | |
157 | +/* #include <asm-i386/timex.h> for timing */ | |
158 | + | |
159 | +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>"); | |
160 | +MODULE_DESCRIPTION("IP tables u32 matching module"); | |
161 | +MODULE_LICENSE("GPL"); | |
162 | + | |
163 | +/* This is slow, but it's simple. --RR */ | |
164 | +static char u32_buffer[65536]; | |
165 | +static DEFINE_SPINLOCK(u32_lock); | |
166 | + | |
167 | +static int | |
168 | +match(const struct sk_buff *skb, | |
169 | + const struct net_device *in, | |
170 | + const struct net_device *out, | |
171 | + const struct xt_match *match, | |
172 | + const void *matchinfo, | |
173 | + int offset, | |
174 | + unsigned int protoff, | |
175 | + int *hotdrop) | |
176 | +{ | |
177 | + const struct ipt_u32 *data = matchinfo; | |
178 | + int testind, i; | |
179 | + unsigned char* base; | |
180 | + unsigned char* head; | |
181 | + int nnums, nvals; | |
182 | + u_int32_t pos, val; | |
183 | + | |
184 | + u_int32_t AttPos; | |
185 | + | |
186 | + spin_lock_bh(&u32_lock); | |
187 | + | |
188 | + head = skb_header_pointer(skb, 0, skb->len, u32_buffer); | |
189 | + BUG_ON(head == NULL); | |
190 | + | |
191 | + base = head; | |
192 | + /* unsigned long long cycles1, cycles2, cycles3, cycles4; | |
193 | + cycles1 = get_cycles(); */ | |
194 | + for (testind=0; testind < data->ntests; testind++) { | |
195 | + AttPos = 0; | |
196 | + pos = data->tests[testind].location[0].number; | |
197 | + if (AttPos + pos + 3 > skb->len || AttPos + pos < 0){ | |
198 | + spin_unlock_bh(&u32_lock); | |
199 | + return 0; | |
200 | + } | |
201 | + val = (base[pos]<<24) + (base[pos+1]<<16) + | |
202 | + (base[pos+2]<<8) + base[pos+3]; | |
203 | + nnums = data->tests[testind].nnums; | |
204 | + for (i=1; i < nnums; i++) { | |
205 | + u_int32_t number = data->tests[testind].location[i].number; | |
206 | + switch (data->tests[testind].location[i].nextop) { | |
207 | + case IPT_U32_AND: | |
208 | + val = val & number; | |
209 | + break; | |
210 | + case IPT_U32_LEFTSH: | |
211 | + val = val << number; | |
212 | + break; | |
213 | + case IPT_U32_RIGHTSH: | |
214 | + val = val >> number; | |
215 | + break; | |
216 | + case IPT_U32_AT: | |
217 | + AttPos += val; | |
218 | + pos = number; | |
219 | + if (AttPos + pos + 3 > skb->len || AttPos + pos < 0) { | |
220 | + spin_unlock_bh(&u32_lock); | |
221 | + return 0; | |
222 | + } | |
223 | + | |
224 | + val = (base[AttPos + pos]<<24) | |
225 | + +(base[AttPos + pos + 1]<<16) | |
226 | + +(base[AttPos + pos + 2]<<8) | |
227 | + + base[AttPos + pos + 3]; | |
228 | + break; | |
229 | + } | |
230 | + } | |
231 | + nvals = data->tests[testind].nvalues; | |
232 | + for (i=0; i < nvals; i++) { | |
233 | + if ((data->tests[testind].value[i].min <= val) && | |
234 | + (val <= data->tests[testind].value[i].max)) { | |
235 | + break; | |
236 | + } | |
237 | + } | |
238 | + if (i >= data->tests[testind].nvalues) { | |
239 | + /* cycles2 = get_cycles(); | |
240 | + printk("failed %d in %d cycles\n", testind, | |
241 | + cycles2-cycles1); */ | |
242 | + spin_unlock_bh(&u32_lock); | |
243 | + return 0; | |
244 | + } | |
245 | + } | |
246 | + /* cycles2 = get_cycles(); | |
247 | + printk("succeeded in %d cycles\n", cycles2-cycles1); */ | |
248 | + spin_unlock_bh(&u32_lock); | |
249 | + return 1; | |
250 | +} | |
251 | + | |
252 | +static int | |
253 | +checkentry(const char *tablename, | |
254 | + const void *ip, | |
255 | + const struct xt_match *match, | |
256 | + void *matchinfo, | |
257 | + /* unsigned int matchsize, */ | |
258 | + unsigned int hook_mask) | |
259 | +{ | |
260 | + if (sizeof(struct ipt_u32) != IPT_ALIGN(sizeof(struct ipt_u32))) | |
261 | + return 0; | |
262 | + return 1; | |
263 | +} | |
264 | + | |
265 | +static struct xt_match u32_match = { | |
266 | + .name = "u32", | |
267 | + .family = AF_INET, | |
268 | + .match = &match, | |
269 | + .matchsize = sizeof(struct ipt_u32), | |
270 | + .checkentry = &checkentry, | |
271 | + .me = THIS_MODULE | |
272 | +}; | |
273 | + | |
274 | +static int __init init(void) | |
275 | +{ | |
276 | + return xt_register_match(&u32_match); | |
277 | +} | |
278 | + | |
279 | +static void __exit fini(void) | |
280 | +{ | |
281 | + xt_unregister_match(&u32_match); | |
282 | +} | |
283 | + | |
284 | +module_init(init); | |
285 | +module_exit(fini); | |
286 | diff -Nru linux-2.6.22/net/ipv4/netfilter/Kconfig linux-2.6.22-pom2patch/net/ipv4/netfilter/Kconfig | |
287 | --- linux-2.6.22/net/ipv4/netfilter/Kconfig 2007-07-09 01:32:17.000000000 +0200 | |
288 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/Kconfig 2007-08-07 18:40:11.000000000 +0200 | |
289 | @@ -402,5 +402,18 @@ | |
290 | Allows altering the ARP packet payload: source and destination | |
291 | hardware and network addresses. | |
292 | ||
293 | +config IP_NF_MATCH_U32 | |
294 | + tristate 'U32 match support' | |
295 | + depends on IP_NF_IPTABLES | |
296 | + help | |
297 | + U32 allows you to extract quantities of up to 4 bytes from a packet, | |
298 | + AND them with specified masks, shift them by specified amounts and | |
299 | + test whether the results are in any of a set of specified ranges. | |
300 | + The specification of what to extract is general enough to skip over | |
301 | + headers with lengths stored in the packet, as in IP or TCP header | |
302 | + lengths. | |
303 | + | |
304 | + Details and examples are in the kernel module source. | |
305 | + | |
306 | endmenu | |
307 | ||
308 | diff -Nru linux-2.6.22/net/ipv4/netfilter/Makefile linux-2.6.22-pom2patch/net/ipv4/netfilter/Makefile | |
309 | --- linux-2.6.22/net/ipv4/netfilter/Makefile 2007-07-09 01:32:17.000000000 +0200 | |
310 | +++ linux-2.6.22-pom2patch/net/ipv4/netfilter/Makefile 2007-08-07 18:40:11.000000000 +0200 | |
311 | @@ -45,6 +45,7 @@ | |
312 | obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o | |
313 | obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o | |
314 | obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o | |
315 | +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o | |
316 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o | |
317 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o | |
318 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o |