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