]> git.pld-linux.org Git - packages/kernel.git/blob - 2.6.1-rc2-NF-u32-20040107.patch
+CONFIG_IP_NF_MATCH_LAYER7=m
[packages/kernel.git] / 2.6.1-rc2-NF-u32-20040107.patch
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
This page took 0.064629 seconds and 3 git commands to generate.