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 | 233 +++++++++++++++++++++++++++++++++
5 4 files changed, 287 insertions(+)
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 01:00:00.000000000 +0100
9 +++ linux/include/linux/netfilter_ipv4/ipt_u32.h 2006-05-04 10:30:23.000000000 +0200
13 +#include <linux/netfilter_ipv4/ip_tables.h>
23 +struct ipt_u32_location_element
28 +struct ipt_u32_value_element
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
39 + struct ipt_u32_location_element location[U32MAXSIZE+1];
41 + struct ipt_u32_value_element value[U32MAXSIZE+1];
47 + struct ipt_u32_test tests[U32MAXSIZE+1];
50 +#endif /*_IPT_U32_H*/
51 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig
52 --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200
53 +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 10:30:23.000000000 +0200
55 Allows altering the ARP packet payload: source and destination
56 hardware and network addresses.
58 +config IP_NF_MATCH_U32
59 + tristate 'U32 match support'
60 + depends on IP_NF_IPTABLES
62 + U32 allows you to extract quantities of up to 4 bytes from a packet,
63 + AND them with specified masks, shift them by specified amounts and
64 + test whether the results are in any of a set of specified ranges.
65 + The specification of what to extract is general enough to skip over
66 + headers with lengths stored in the packet, as in IP or TCP header
69 + Details and examples are in the kernel module source.
73 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
74 --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200
75 +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 10:30:23.000000000 +0200
77 +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
78 diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_u32.c linux/net/ipv4/netfilter/ipt_u32.c
79 --- linux.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100
80 +++ linux/net/ipv4/netfilter/ipt_u32.c 2006-05-04 10:30:23.000000000 +0200
82 +/* Kernel module to match u32 packet content. */
85 +U32 tests whether quantities of up to 4 bytes extracted from a packet
86 +have specified values. The specification of what to extract is general
87 +enough to find data at given offsets from tcp headers or payloads.
90 + The argument amounts to a program in a small language described below.
91 + tests := location = value | tests && location = value
92 + value := range | value , range
93 + range := number | number : number
94 + a single number, n, is interpreted the same as n:n
95 + n:m is interpreted as the range of numbers >=n and <=m
96 + location := number | location operator number
97 + operator := & | << | >> | @
99 + The operators &, <<, >>, && mean the same as in c. The = is really a set
100 + membership operator and the value syntax describes a set. The @ operator
101 + is what allows moving to the next header and is described further below.
103 + *** Until I can find out how to avoid it, there are some artificial limits
104 + on the size of the tests:
105 + - no more than 10 ='s (and 9 &&'s) in the u32 argument
106 + - no more than 10 ranges (and 9 commas) per value
107 + - no more than 10 numbers (and 9 operators) per location
109 + To describe the meaning of location, imagine the following machine that
110 + interprets it. There are three registers:
111 + A is of type char*, initially the address of the IP header
112 + B and C are unsigned 32 bit integers, initially zero
114 + The instructions are:
116 + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
117 + &number C = C&number
118 + <<number C = C<<number
119 + >>number C = C>>number
120 + @number A = A+C; then do the instruction number
121 + Any access of memory outside [skb->head,skb->end] causes the match to fail.
122 + Otherwise the result of the computation is the final value of C.
124 + Whitespace is allowed but not required in the tests.
125 + However the characters that do occur there are likely to require
126 + shell quoting, so it's a good idea to enclose the arguments in quotes.
129 + match IP packets with total length >= 256
130 + The IP header contains a total length field in bytes 2-3.
131 + --u32 "0&0xFFFF=0x100:0xFFFF"
133 + AND that with FFFF (giving bytes 2-3),
134 + and test whether that's in the range [0x100:0xFFFF]
136 +Example: (more realistic, hence more complicated)
137 + match icmp packets with icmp type 0
138 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1
139 + --u32 "6&0xFF=1 && ...
140 + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
141 + Next test that it's not a fragment.
142 + (If so it might be part of such a packet but we can't always tell.)
143 + n.b. This test is generally needed if you want to match anything
144 + beyond the IP header.
145 + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
146 + packet (not a fragment). Alternatively, you can allow first fragments
147 + by only testing the last 5 bits of byte 6.
148 + ... 4&0x3FFF=0 && ...
149 + Last test: the first byte past the IP header (the type) is 0
150 + This is where we have to use the @syntax. The length of the IP header
151 + (IHL) in 32 bit words is stored in the right half of byte 0 of the
153 + ... 0>>22&0x3C@0>>24=0"
154 + The first 0 means read bytes 0-3,
155 + >>22 means shift that 22 bits to the right. Shifting 24 bits would give
156 + the first byte, so only 22 bits is four times that plus a few more bits.
157 + &3C then eliminates the two extra bits on the right and the first four
158 + bits of the first byte.
159 + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
160 + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
161 + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
162 + @ means to use this number as a new offset into the packet, and read
163 + four bytes starting from there. This is the first 4 bytes of the icmp
164 + payload, of which byte 0 is the icmp type. Therefore we simply shift
165 + the value 24 to the right to throw out all but the first byte and compare
169 + tcp payload bytes 8-12 is any of 1, 2, 5 or 8
170 + First we test that the packet is a tcp packet (similar to icmp).
171 + --u32 "6&0xFF=6 && ...
172 + Next, test that it's not a fragment (same as above).
173 + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8"
174 + 0>>22&3C as above computes the number of bytes in the IP header.
175 + @ makes this the new offset into the packet, which is the start of the
176 + tcp header. The length of the tcp header (again in 32 bit words) is
177 + the left half of byte 12 of the tcp header. The 12>>26&3C
178 + computes this length in bytes (similar to the IP header before).
179 + @ makes this the new offset, which is the start of the tcp payload.
180 + Finally 8 reads bytes 8-12 of the payload and = checks whether the
181 + result is any of 1, 2, 5 or 8
184 +#include <linux/module.h>
185 +#include <linux/skbuff.h>
187 +#include <linux/netfilter_ipv4/ipt_u32.h>
188 +#include <linux/netfilter_ipv4/ip_tables.h>
190 +/* #include <asm-i386/timex.h> for timing */
192 +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
193 +MODULE_DESCRIPTION("IP tables u32 matching module");
194 +MODULE_LICENSE("GPL");
196 +/* This is slow, but it's simple. --RR */
197 +static char u32_buffer[65536];
198 +static DEFINE_SPINLOCK(u32_lock);
201 +match(const struct sk_buff *skb,
202 + const struct net_device *in,
203 + const struct net_device *out,
204 + const void *matchinfo,
206 + unsigned int protoff,
209 + const struct ipt_u32 *data = matchinfo;
211 + unsigned char* base;
212 + unsigned char* head;
214 + u_int32_t pos, val;
218 + spin_lock_bh(&u32_lock);
220 + head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
221 + BUG_ON(head == NULL);
224 + /* unsigned long long cycles1, cycles2, cycles3, cycles4;
225 + cycles1 = get_cycles(); */
226 + for (testind=0; testind < data->ntests; testind++) {
228 + pos = data->tests[testind].location[0].number;
229 + if (AttPos + pos + 3 > skb->len || AttPos + pos < 0){
230 + spin_unlock_bh(&u32_lock);
233 + val = (base[pos]<<24) + (base[pos+1]<<16) +
234 + (base[pos+2]<<8) + base[pos+3];
235 + nnums = data->tests[testind].nnums;
236 + for (i=1; i < nnums; i++) {
237 + u_int32_t number = data->tests[testind].location[i].number;
238 + switch (data->tests[testind].location[i].nextop) {
240 + val = val & number;
242 + case IPT_U32_LEFTSH:
243 + val = val << number;
245 + case IPT_U32_RIGHTSH:
246 + val = val >> number;
251 + if (AttPos + pos + 3 > skb->len || AttPos + pos < 0) {
252 + spin_unlock_bh(&u32_lock);
256 + val = (base[AttPos + pos]<<24)
257 + +(base[AttPos + pos + 1]<<16)
258 + +(base[AttPos + pos + 2]<<8)
259 + + base[AttPos + pos + 3];
263 + nvals = data->tests[testind].nvalues;
264 + for (i=0; i < nvals; i++) {
265 + if ((data->tests[testind].value[i].min <= val) &&
266 + (val <= data->tests[testind].value[i].max)) {
270 + if (i >= data->tests[testind].nvalues) {
271 + /* cycles2 = get_cycles();
272 + printk("failed %d in %d cycles\n", testind,
273 + cycles2-cycles1); */
274 + spin_unlock_bh(&u32_lock);
278 + /* cycles2 = get_cycles();
279 + printk("succeeded in %d cycles\n", cycles2-cycles1); */
280 + spin_unlock_bh(&u32_lock);
285 +checkentry(const char *tablename,
286 + const struct ipt_ip *ip,
288 + unsigned int matchsize,
289 + unsigned int hook_mask)
291 + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
296 +static struct ipt_match u32_match = {
299 + .checkentry = &checkentry,
303 +static int __init init(void)
305 + return ipt_register_match(&u32_match);
308 +static void __exit fini(void)
310 + ipt_unregister_match(&u32_match);