]> git.pld-linux.org Git - packages/kernel.git/blame - pom-ng-u32-20060829.patch
- ppc configs updated, rel 0.7
[packages/kernel.git] / pom-ng-u32-20060829.patch
CommitLineData
133b4e72 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
7diff -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*/
51diff -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);
291diff -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
313diff -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.078015 seconds and 4 git commands to generate.