]>
Commit | Line | Data |
---|---|---|
9e5a6bf4 | 1 | diff -Nur linux-2.6.1-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.1-rc2/include/linux/netfilter_ipv4/ipt_u32.h |
2 | --- linux-2.6.1-rc2.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ linux-2.6.1-rc2/include/linux/netfilter_ipv4/ipt_u32.h 2004-01-07 19:48:17.617271144 +0100 | |
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 -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.1-rc2/net/ipv4/netfilter/ipt_u32.c | |
46 | --- linux-2.6.1-rc2.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100 | |
47 | +++ linux-2.6.1-rc2/net/ipv4/netfilter/ipt_u32.c 2004-01-07 19:48:17.618270992 +0100 | |
48 | @@ -0,0 +1,211 @@ | |
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 | +static int | |
164 | +match(const struct sk_buff *skb, | |
165 | + const struct net_device *in, | |
166 | + const struct net_device *out, | |
167 | + const void *matchinfo, | |
168 | + int offset, | |
169 | + const void *hdr, | |
170 | + u_int16_t datalen, | |
171 | + int *hotdrop) | |
172 | +{ | |
173 | + const struct ipt_u32 *data = matchinfo; | |
174 | + int testind, i; | |
175 | + unsigned char* origbase = (char*)skb->nh.iph; | |
176 | + unsigned char* base = origbase; | |
177 | + unsigned char* head = skb->head; | |
178 | + unsigned char* end = skb->end; | |
179 | + int nnums, nvals; | |
180 | + u_int32_t pos, val; | |
181 | + /* unsigned long long cycles1, cycles2, cycles3, cycles4; | |
182 | + cycles1 = get_cycles(); */ | |
183 | + | |
184 | + for (testind=0; testind < data->ntests; testind++) { | |
185 | + base = origbase; /* reset for each test */ | |
186 | + pos = data->tests[testind].location[0].number; | |
187 | + if (base+pos+3 > end || base+pos < head) | |
188 | + return 0; | |
189 | + val = (base[pos]<<24) + (base[pos+1]<<16) + | |
190 | + (base[pos+2]<<8) + base[pos+3]; | |
191 | + nnums = data->tests[testind].nnums; | |
192 | + for (i=1; i < nnums; i++) { | |
193 | + u_int32_t number = data->tests[testind].location[i].number; | |
194 | + switch (data->tests[testind].location[i].nextop) { | |
195 | + case IPT_U32_AND: | |
196 | + val = val & number; | |
197 | + break; | |
198 | + case IPT_U32_LEFTSH: | |
199 | + val = val << number; | |
200 | + break; | |
201 | + case IPT_U32_RIGHTSH: | |
202 | + val = val >> number; | |
203 | + break; | |
204 | + case IPT_U32_AT: | |
205 | + base = base + val; | |
206 | + pos = number; | |
207 | + if (base+pos+3 > end || base+pos < head) | |
208 | + return 0; | |
209 | + val = (base[pos]<<24) + (base[pos+1]<<16) + | |
210 | + (base[pos+2]<<8) + base[pos+3]; | |
211 | + break; | |
212 | + } | |
213 | + } | |
214 | + nvals = data->tests[testind].nvalues; | |
215 | + for (i=0; i < nvals; i++) { | |
216 | + if ((data->tests[testind].value[i].min <= val) && | |
217 | + (val <= data->tests[testind].value[i].max)) { | |
218 | + break; | |
219 | + } | |
220 | + } | |
221 | + if (i >= data->tests[testind].nvalues) { | |
222 | + /* cycles2 = get_cycles(); | |
223 | + printk("failed %d in %d cycles\n", testind, | |
224 | + cycles2-cycles1); */ | |
225 | + return 0; | |
226 | + } | |
227 | + } | |
228 | + /* cycles2 = get_cycles(); | |
229 | + printk("succeeded in %d cycles\n", cycles2-cycles1); */ | |
230 | + return 1; | |
231 | +} | |
232 | + | |
233 | +static int | |
234 | +checkentry(const char *tablename, | |
235 | + const struct ipt_ip *ip, | |
236 | + void *matchinfo, | |
237 | + unsigned int matchsize, | |
238 | + unsigned int hook_mask) | |
239 | +{ | |
240 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32))) | |
241 | + return 0; | |
242 | + return 1; | |
243 | +} | |
244 | + | |
245 | +static struct ipt_match u32_match | |
246 | += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE }; | |
247 | + | |
248 | +static int __init init(void) | |
249 | +{ | |
250 | + return ipt_register_match(&u32_match); | |
251 | +} | |
252 | + | |
253 | +static void __exit fini(void) | |
254 | +{ | |
255 | + ipt_unregister_match(&u32_match); | |
256 | +} | |
257 | + | |
258 | +module_init(init); | |
259 | +module_exit(fini); | |
260 | diff -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/Kconfig linux-2.6.1-rc2/net/ipv4/netfilter/Kconfig | |
261 | --- linux-2.6.1-rc2.org/net/ipv4/netfilter/Kconfig 2004-01-07 19:36:33.000000000 +0100 | |
262 | +++ linux-2.6.1-rc2/net/ipv4/netfilter/Kconfig 2004-01-07 19:48:17.620270688 +0100 | |
263 | @@ -596,5 +596,18 @@ | |
264 | will match the packets (locally generated) that have a departure timestamp | |
265 | in the range 8:00->18:00 on Monday only. | |
266 | ||
267 | +config IP_NF_MATCH_U32 | |
268 | + tristate 'U32 match support' | |
269 | + depends on IP_NF_IPTABLES | |
270 | + help | |
271 | + | |
272 | + U32 allows you to extract quantities of up to 4 bytes from a packet, | |
273 | + AND them with specified masks, shift them by specified amounts and | |
274 | + test whether the results are in any of a set of specified ranges. | |
275 | + The specification of what to extract is general enough to skip over | |
276 | + headers with lengths stored in the packet, as in IP or TCP header | |
277 | + lengths. | |
278 | + Details and examples are in the kernel module source. | |
279 | + | |
280 | endmenu | |
281 | ||
282 | diff -Nur linux-2.6.1-rc2.org/net/ipv4/netfilter/Makefile linux-2.6.1-rc2/net/ipv4/netfilter/Makefile | |
283 | --- linux-2.6.1-rc2.org/net/ipv4/netfilter/Makefile 2004-01-07 19:36:33.000000000 +0100 | |
284 | +++ linux-2.6.1-rc2/net/ipv4/netfilter/Makefile 2004-01-07 19:48:17.621270536 +0100 | |
285 | @@ -62,6 +62,9 @@ | |
286 | ||
287 | obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o | |
288 | ||
289 | +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o | |
290 | + | |
291 | + | |
292 | obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | |
293 | obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o | |
294 | obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o |