netfilter-2.6/patch-o-matic-ng/trunk: include/linux/netfilter_ipv4/ipt_u32.h net/ipv4/netfilter/Kcon...

pluto cvs at pld-linux.org
Thu Jul 28 16:29:49 CEST 2005


Author: pluto
Date: Thu Jul 28 16:29:45 2005
New Revision: 6268

Added:
   netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ipt_u32.h
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ipt_u32.c
Modified:
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Kconfig
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile
   netfilter-2.6/patch-o-matic-ng/trunk/status
Log:
- u32.


Added: netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ipt_u32.h
==============================================================================
--- (empty file)
+++ netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ipt_u32.h	Thu Jul 28 16:29:45 2005
@@ -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*/

Modified: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Kconfig
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Kconfig	(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Kconfig	Thu Jul 28 16:29:45 2005
@@ -1253,5 +1253,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
 

Modified: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile	(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile	Thu Jul 28 16:29:45 2005
@@ -89,6 +89,9 @@
 obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
 obj-$(CONFIG_IP_NF_MATCH_AH_ESP) += ipt_ah.o ipt_esp.o
 obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o
+
+obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o
+
 obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
 obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
 obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o

Added: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ipt_u32.c
==============================================================================
--- (empty file)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ipt_u32.c	Thu Jul 28 16:29:45 2005
@@ -0,0 +1,231 @@
+/* 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;
+
+	LOCK_BH(&u32_lock);
+
+	head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
+	BUG_ON(head == NULL);
+
+	origbase = head + (((void *)skb->nh.iph) - ((void *)skb->head));
+	end = head + (skb->end - skb->head);
+	base = origbase;
+
+	/* unsigned long long cycles1, cycles2, cycles3, cycles4;
+	   cycles1 = get_cycles(); */
+	for (testind=0; testind < data->ntests; testind++) {
+		base = origbase; /* reset for each test */
+		pos = data->tests[testind].location[0].number;
+		if (base+pos+3 > end || base+pos < head) {
+			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:
+				base = base + val;
+				pos = number;
+				if (base+pos+3 > end || base+pos < head) 
+					return 0;
+				val = (base[pos]<<24) + (base[pos+1]<<16) +
+					(base[pos+2]<<8) + base[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);

Modified: netfilter-2.6/patch-o-matic-ng/trunk/status
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/status	(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/status	Thu Jul 28 16:29:45 2005
@@ -39,7 +39,7 @@
 TARPIT			2005/07/27	added
 time			2005/07/27	added
 TTL			2005/07/27	added
-u32					added+updated
+u32			2005/07/27	added
 ULOG					updated
 unclean			2005/07/27	added
 XOR			2005/07/27	added



More information about the pld-cvs-commit mailing list