SOURCES (LINUX_2_6): linux-2.6-nf-u32.patch (NEW) - [base] u32 mat...
pluto
pluto at pld-linux.org
Thu Sep 15 10:41:16 CEST 2005
Author: pluto Date: Thu Sep 15 08:41:16 2005 GMT
Module: SOURCES Tag: LINUX_2_6
---- Log message:
- [base] u32 match (NEEDS REWORK FOR 2.6.13, i'll do it later).
---- Files affected:
SOURCES:
linux-2.6-nf-u32.patch (NONE -> 1.1.2.1) (NEW)
---- Diffs:
================================================================
Index: SOURCES/linux-2.6-nf-u32.patch
diff -u /dev/null SOURCES/linux-2.6-nf-u32.patch:1.1.2.1
--- /dev/null Thu Sep 15 10:41:16 2005
+++ SOURCES/linux-2.6-nf-u32.patch Thu Sep 15 10:41:11 2005
@@ -0,0 +1,314 @@
+ include/linux/netfilter_ipv4/ipt_u32.h | 40 +++++
+ net/ipv4/netfilter/Kconfig | 13 +
+ net/ipv4/netfilter/Makefile | 3
+ net/ipv4/netfilter/ipt_u32.c | 233 +++++++++++++++++++++++++++++++++
+ 4 files changed, 289 insertions(+)
+
+diff -uNr linux-2.6.13.1/include.orig/linux/netfilter_ipv4/ipt_u32.h linux-2.6.13.1/include/linux/netfilter_ipv4/ipt_u32.h
+--- linux-2.6.13.1/include.orig/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.13.1/include/linux/netfilter_ipv4/ipt_u32.h 2005-09-15 10:39:55.322807250 +0200
+@@ -0,0 +1,40 @@
++#ifndef _IPT_U32_H
++#define _IPT_U32_H
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++enum ipt_u32_ops
++{
++ IPT_U32_AND,
++ IPT_U32_LEFTSH,
++ IPT_U32_RIGHTSH,
++ IPT_U32_AT
++};
++
++struct ipt_u32_location_element
++{
++ u_int32_t number;
++ u_int8_t nextop;
++};
++struct ipt_u32_value_element
++{
++ u_int32_t min;
++ u_int32_t max;
++};
++/* *** any way to allow for an arbitrary number of elements?
++ for now I settle for a limit of 10 of each */
++#define U32MAXSIZE 10
++struct ipt_u32_test
++{
++ u_int8_t nnums;
++ struct ipt_u32_location_element location[U32MAXSIZE+1];
++ u_int8_t nvalues;
++ struct ipt_u32_value_element value[U32MAXSIZE+1];
++};
++
++struct ipt_u32
++{
++ u_int8_t ntests;
++ struct ipt_u32_test tests[U32MAXSIZE+1];
++};
++
++#endif /*_IPT_U32_H*/
+diff -uNr linux-2.6.13.1/net.orig/ipv4/netfilter/ipt_u32.c linux-2.6.13.1/net/ipv4/netfilter/ipt_u32.c
+--- linux-2.6.13.1/net.orig/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.13.1/net/ipv4/netfilter/ipt_u32.c 2005-09-15 10:39:55.326807500 +0200
+@@ -0,0 +1,233 @@
++/* Kernel module to match u32 packet content. */
++
++/*
++U32 tests whether quantities of up to 4 bytes extracted from a packet
++have specified values. The specification of what to extract is general
++enough to find data at given offsets from tcp headers or payloads.
++
++ --u32 tests
++ The argument amounts to a program in a small language described below.
++ tests := location = value | tests && location = value
++ value := range | value , range
++ range := number | number : number
++ a single number, n, is interpreted the same as n:n
++ n:m is interpreted as the range of numbers >=n and <=m
++ location := number | location operator number
++ operator := & | << | >> | @
++
++ The operators &, <<, >>, && mean the same as in c. The = is really a set
++ membership operator and the value syntax describes a set. The @ operator
++ is what allows moving to the next header and is described further below.
++
++ *** Until I can find out how to avoid it, there are some artificial limits
++ on the size of the tests:
++ - no more than 10 ='s (and 9 &&'s) in the u32 argument
++ - no more than 10 ranges (and 9 commas) per value
++ - no more than 10 numbers (and 9 operators) per location
++
++ To describe the meaning of location, imagine the following machine that
++ interprets it. There are three registers:
++ A is of type char*, initially the address of the IP header
++ B and C are unsigned 32 bit integers, initially zero
++
++ The instructions are:
++ number B = number;
++ C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3)
++ &number C = C&number
++ <<number C = C<<number
++ >>number C = C>>number
++ @number A = A+C; then do the instruction number
++ Any access of memory outside [skb->head,skb->end] causes the match to fail.
++ Otherwise the result of the computation is the final value of C.
++
++ Whitespace is allowed but not required in the tests.
++ However the characters that do occur there are likely to require
++ shell quoting, so it's a good idea to enclose the arguments in quotes.
++
++Example:
++ match IP packets with total length >= 256
++ The IP header contains a total length field in bytes 2-3.
++ --u32 "0&0xFFFF=0x100:0xFFFF"
++ read bytes 0-3
++ AND that with FFFF (giving bytes 2-3),
++ and test whether that's in the range [0x100:0xFFFF]
++
++Example: (more realistic, hence more complicated)
++ match icmp packets with icmp type 0
++ First test that it's an icmp packet, true iff byte 9 (protocol) = 1
++ --u32 "6&0xFF=1 && ...
++ read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1
++ Next test that it's not a fragment.
++ (If so it might be part of such a packet but we can't always tell.)
++ n.b. This test is generally needed if you want to match anything
++ beyond the IP header.
++ The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete
++ packet (not a fragment). Alternatively, you can allow first fragments
++ by only testing the last 5 bits of byte 6.
++ ... 4&0x3FFF=0 && ...
++ Last test: the first byte past the IP header (the type) is 0
++ This is where we have to use the @syntax. The length of the IP header
++ (IHL) in 32 bit words is stored in the right half of byte 0 of the
++ IP header itself.
++ ... 0>>22&0x3C at 0>>24=0"
++ The first 0 means read bytes 0-3,
++ >>22 means shift that 22 bits to the right. Shifting 24 bits would give
++ the first byte, so only 22 bits is four times that plus a few more bits.
++ &3C then eliminates the two extra bits on the right and the first four
++ bits of the first byte.
++ For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long.
++ In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz,
++ >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100.
++ @ means to use this number as a new offset into the packet, and read
++ four bytes starting from there. This is the first 4 bytes of the icmp
++ payload, of which byte 0 is the icmp type. Therefore we simply shift
++ the value 24 to the right to throw out all but the first byte and compare
++ the result with 0.
++
++Example:
++ tcp payload bytes 8-12 is any of 1, 2, 5 or 8
++ First we test that the packet is a tcp packet (similar to icmp).
++ --u32 "6&0xFF=6 && ...
++ Next, test that it's not a fragment (same as above).
++ ... 0>>22&0x3C at 12>>26&0x3C at 8=1,2,5,8"
++ 0>>22&3C as above computes the number of bytes in the IP header.
++ @ makes this the new offset into the packet, which is the start of the
++ tcp header. The length of the tcp header (again in 32 bit words) is
++ the left half of byte 12 of the tcp header. The 12>>26&3C
++ computes this length in bytes (similar to the IP header before).
++ @ makes this the new offset, which is the start of the tcp payload.
++ Finally 8 reads bytes 8-12 of the payload and = checks whether the
++ result is any of 1, 2, 5 or 8
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ipt_u32.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++/* #include <asm-i386/timex.h> for timing */
++
++MODULE_AUTHOR("Don Cohen <don at isis.cs3-inc.com>");
++MODULE_DESCRIPTION("IP tables u32 matching module");
++MODULE_LICENSE("GPL");
++
++/* This is slow, but it's simple. --RR */
++static char u32_buffer[65536];
++static DECLARE_LOCK(u32_lock);
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_u32 *data = matchinfo;
++ int testind, i;
++ unsigned char* origbase;
++ unsigned char* base;
++ unsigned char* head;
++ unsigned char* end;
++ int nnums, nvals;
++ u_int32_t pos, val;
++
++ u_int32_t AttPos;
++
++ LOCK_BH(&u32_lock);
++
++ head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
++ BUG_ON(head == NULL);
++
++ base = head;
++ /* unsigned long long cycles1, cycles2, cycles3, cycles4;
++ cycles1 = get_cycles(); */
++ for (testind=0; testind < data->ntests; testind++) {
++ AttPos = 0;
++ pos = data->tests[testind].location[0].number;
++ if (AttPos + pos + 3 > skb->len || AttPos + pos < 0){
++ UNLOCK_BH(&u32_lock);
++ return 0;
++ }
++ val = (base[pos]<<24) + (base[pos+1]<<16) +
++ (base[pos+2]<<8) + base[pos+3];
++ nnums = data->tests[testind].nnums;
++ for (i=1; i < nnums; i++) {
++ u_int32_t number = data->tests[testind].location[i].number;
++ switch (data->tests[testind].location[i].nextop) {
++ case IPT_U32_AND:
++ val = val & number;
++ break;
++ case IPT_U32_LEFTSH:
++ val = val << number;
++ break;
++ case IPT_U32_RIGHTSH:
++ val = val >> number;
++ break;
++ case IPT_U32_AT:
++ AttPos += val;
++ pos = number;
++ if (AttPos + pos + 3 > skb->len || AttPos + pos < 0)
++ return 0;
++
++ val = (base[AttPos + pos]<<24)
++ +(base[AttPos + pos + 1]<<16)
++ +(base[AttPos + pos + 2]<<8)
++ + base[AttPos + pos + 3];
++ break;
++ }
++ }
++ nvals = data->tests[testind].nvalues;
++ for (i=0; i < nvals; i++) {
++ if ((data->tests[testind].value[i].min <= val) &&
++ (val <= data->tests[testind].value[i].max)) {
++ break;
++ }
++ }
++ if (i >= data->tests[testind].nvalues) {
++ /* cycles2 = get_cycles();
++ printk("failed %d in %d cycles\n", testind,
++ cycles2-cycles1); */
++ UNLOCK_BH(&u32_lock);
++ return 0;
++ }
++ }
++ /* cycles2 = get_cycles();
++ printk("succeeded in %d cycles\n", cycles2-cycles1); */
++ UNLOCK_BH(&u32_lock);
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32)))
++ return 0;
++ return 1;
++}
++
++static struct ipt_match u32_match = {
++ .name = "u32",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&u32_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&u32_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -uNr linux-2.6.13.1/net.orig/ipv4/netfilter/Kconfig linux-2.6.13.1/net/ipv4/netfilter/Kconfig
+--- linux-2.6.13.1/net.orig/ipv4/netfilter/Kconfig 2005-09-15 10:39:20.000000000 +0200
++++ linux-2.6.13.1/net/ipv4/netfilter/Kconfig 2005-09-15 10:39:55.330807750 +0200
+@@ -884,5 +884,18 @@
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
++config IP_NF_MATCH_U32
++ tristate 'U32 match support'
++ depends on IP_NF_IPTABLES
++ help
++ U32 allows you to extract quantities of up to 4 bytes from a packet,
++ AND them with specified masks, shift them by specified amounts and
++ test whether the results are in any of a set of specified ranges.
++ The specification of what to extract is general enough to skip over
++ headers with lengths stored in the packet, as in IP or TCP header
++ lengths.
++
++ Details and examples are in the kernel module source.
++
+ endmenu
+
+diff -uNr linux-2.6.13.1/net.orig/ipv4/netfilter/Makefile linux-2.6.13.1/net/ipv4/netfilter/Makefile
+--- linux-2.6.13.1/net.orig/ipv4/netfilter/Makefile 2005-09-15 10:39:20.000000000 +0200
++++ linux-2.6.13.1/net/ipv4/netfilter/Makefile 2005-09-15 10:39:55.334808000 +0200
+@@ -0,0 +0,1 @@
++obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
================================================================
More information about the pld-cvs-commit
mailing list