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