All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH][IPTABLES] userspace u32 match support
@ 2006-11-10  1:31 Pablo Neira Ayuso
  2006-11-15  9:19 ` Krzysztof Oledzki
  0 siblings, 1 reply; 4+ messages in thread
From: Pablo Neira Ayuso @ 2006-11-10  1:31 UTC (permalink / raw)
  To: Netfilter Development Mailinglist
  Cc: Harald Welte, Michael Rash, Patrick McHardy

[-- Attachment #1: Type: text/plain, Size: 185 bytes --]

Add support for u32 match in userspace

-- 
The dawn of the fourth age of Linux firewalling is coming; a time of
great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris

[-- Attachment #2: u32.patch --]
[-- Type: text/plain, Size: 11853 bytes --]

Index: extensions/libipt_u32.c
===================================================================
--- extensions/libipt_u32.c	(revisión: 6678)
+++ extensions/libipt_u32.c	(copia de trabajo)
@@ -1,264 +1,159 @@
-/* Shared library add-on to iptables to add u32 matching,
- * generalized matching on values found at packet offsets
- *
- * Detailed doc is in the kernel module source
- * net/ipv4/netfilter/ipt_u32.c
- *
- * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
- * Released under the terms of GNU GPL v2
+/* Shared library add-on to iptables to add u32 matching. 
+ * 
+ * Copyright (C) 2006 Pablo Neira Ayuso <pablo@netfilter.org>
  */
 #include <stdio.h>
 #include <netdb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <getopt.h>
+#include <ctype.h>
 #include <iptables.h>
 #include <linux/netfilter_ipv4/ipt_u32.h>
-#include <errno.h>
-#include <ctype.h>
 
 /* Function which prints out usage message. */
-static void
-help(void)
+static void help(void)
 {
-	printf( "u32 v%s options:\n"
-		" --u32 tests\n"
-		" tests := location = value | tests && location = value\n"
-		" value := range | value , range\n"
-		" range := number | number : number\n"
-		" location := number | location operator number\n"
-		" operator := & | << | >> | @\n"
-		,IPTABLES_VERSION);
+	printf("U32 match options:\n"
+	       "--offset integer             offset\n"
+	       "--mask xhhxhhxhhxhh          32 bits hexadecimal mask\n"
+	       "--value [!] xhhxhhxhhxhh     32 bits hexadecimal value\n");
 }
 
-/* defined in /usr/include/getopt.h maybe in man getopt */
 static struct option opts[] = {
-	{ "u32", 1, 0, '1' },
-	{ 0 }
+	{ "offset", 1, 0, '1' },
+	{ "mask", 1, 0, '2' },
+	{ "value", 1, 0, '3' },
+	{0}
 };
 
-/* shared printing code */
-static void print_u32(struct ipt_u32 *data)
+static void init(struct ipt_entry_match *m, unsigned int *nfcache)
 {
-	unsigned int testind;
+	struct ipt_u32_info *info = (struct ipt_u32_info *) m->data;
 
-	for (testind=0; testind < data->ntests; testind++) {
-		if (testind) printf("&&");
-		{
-			unsigned int i;
-
-			printf("0x%x", data->tests[testind].location[0].number);
-			for (i = 1; i < data->tests[testind].nnums; i++) {
-				switch (data->tests[testind].location[i].nextop) {
-				case IPT_U32_AND: printf("&"); break;
-				case IPT_U32_LEFTSH: printf("<<"); break;
-				case IPT_U32_RIGHTSH: printf(">>"); break;
-				case IPT_U32_AT: printf("@"); break;
-				}
-				printf("0x%x", data->tests[testind].location[i].number);
-			}
-			printf("=");
-			for (i = 0; i < data->tests[testind].nvalues; i++) {
-				if (i) printf(",");
-				if (data->tests[testind].value[i].min
-				    == data->tests[testind].value[i].max)
-					printf("0x%x", data->tests[testind].value[i].min);
-				else printf("0x%x:0x%x", data->tests[testind].value[i].min,
-					    data->tests[testind].value[i].max);
-			}
-		}
-	}
-	printf(" ");
+	info->mask = 0xffffffff;
 }
 
-/* string_to_number is not quite what we need here ... */
-u_int32_t parse_number(char **s, int pos)
+static int parse_hex(const char *str, unsigned int *res)
 {
-	u_int32_t number;
-	char *end;
-	errno = 0;
+	int a, b, c, d;
 
-	number = strtoul(*s, &end, 0);
-	if (end == *s)
-		exit_error(PARAMETER_PROBLEM, 
-			   "u32: at char %d expected number", pos);
-	if (errno)
-		exit_error(PARAMETER_PROBLEM, 
-			   "u32: at char %d error reading number", pos);
-	*s = end;
-	return number;
+	if (sscanf(str, "x%2xx%2xx%2xx%2x", &a, &b, &c, &d) != 4)
+		return -1;
+
+	*res = (a << 24) | (b << 16) | (c << 8) | d;
+
+	return 0;
 }
 
-/* Function which parses command options; returns true if it ate an option */
-static int
-parse(int c, char **argv, int invert, unsigned int *flags,
-      const struct ipt_entry *entry,
-      unsigned int *nfcache,
-      struct ipt_entry_match **match)
+#define OFFSET 0x1
+#define MASK   0x2
+#define VALUE  0x4
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+		 const struct ipt_entry *entry, unsigned int *nfcache,
+		 struct ipt_entry_match **match)
 {
-	struct ipt_u32 *data = (struct ipt_u32 *)(*match)->data;
-	char *arg = argv[optind-1]; /* the argument string */
-	char *start = arg;
-	int state=0, testind=0, locind=0, valind=0;
+	struct ipt_u32_info *info = (struct ipt_u32_info *)(*match)->data;
 
-	if (c != '1') return 0;
-	/* states: 0 = looking for numbers and operations, 1 = looking for ranges */
-	while (1) { /* read next operand/number or range */
-		while (isspace(*arg)) 
-			arg++;  /* skip white space */
-		if (! *arg) { /* end of argument found */
-			if (state == 0)
-				exit_error(PARAMETER_PROBLEM, 
-					   "u32: input ended in location spec");
-			if (valind == 0)
-				exit_error(PARAMETER_PROBLEM, 
-					   "u32: test ended with no value spec");
-			data->tests[testind].nnums = locind;
-			data->tests[testind].nvalues = valind;
-			testind++;
-			data->ntests=testind;
-			if (testind > U32MAXSIZE)
-				exit_error(PARAMETER_PROBLEM, 
-					   "u32: at char %d too many &&'s",
-					   arg-start);
-			/* debugging 
-			   print_u32(data);printf("\n");
-			   exit_error(PARAMETER_PROBLEM, "debugging output done"); */
-			return 1;
-		}
-		if (state == 0) {
-			/* reading location: read a number if nothing read yet,
-			   otherwise either op number or = to end location spec */	 
-			if (*arg == '=') {
-				if (locind == 0)
-					exit_error(PARAMETER_PROBLEM,
-						   "u32: at char %d location spec missing", arg-start);
-				else {
-					arg++; 
-					state=1;
-				}
-			}
-			else {
-				if (locind) { /* need op before number */
-					if (*arg == '&') {
-						data->tests[testind].location[locind].nextop = IPT_U32_AND;
-					}
-					else if (*arg == '<') {
-						arg++;
-						if (*arg != '<')
-							exit_error(PARAMETER_PROBLEM,
-								   "u32: at char %d a second < expected", arg-start);
-						data->tests[testind].location[locind].nextop = IPT_U32_LEFTSH;
-					}
-					else if (*arg == '>') {
-						arg++;
-						if (*arg != '>')
-							exit_error(PARAMETER_PROBLEM,
-								   "u32: at char %d a second > expected", arg-start);
-						data->tests[testind].location[locind].nextop = IPT_U32_RIGHTSH;
-					}
-					else if (*arg == '@') {
-						data->tests[testind].location[locind].nextop = IPT_U32_AT;
-					}
-					else exit_error(PARAMETER_PROBLEM,
-							"u32: at char %d operator expected", arg-start);
-					arg++;
-				}
-				/* now a number; string_to_number skips white space? */
-				data->tests[testind].location[locind].number =
-					parse_number(&arg, arg-start);
-				locind++;
-				if (locind > U32MAXSIZE)
-					exit_error(PARAMETER_PROBLEM,
-						   "u32: at char %d too many operators", arg-start);
-			}
-		}
-		else {
-			/* state 1 - reading values: read a range if nothing read yet,
-			   otherwise either ,range or && to end test spec */
-			if (*arg == '&') {
-				arg++;
-				if (*arg != '&')
-					exit_error(PARAMETER_PROBLEM,
-						   "u32: at char %d a second & expected", arg-start);
-				if (valind == 0)
-					exit_error(PARAMETER_PROBLEM,
-						   "u32: at char %d value spec missing", arg-start);
-				else {
-					data->tests[testind].nnums = locind;
-					data->tests[testind].nvalues = valind;
-					testind++;
-					if (testind > U32MAXSIZE)
-						exit_error(PARAMETER_PROBLEM,
-							   "u32: at char %d too many &&'s", arg-start);
-					arg++; state=0; locind=0; valind=0;
-				}
-			}
-			else { /* read value range */
-				if (valind) { /* need , before number */
-					if (*arg != ',')
-						exit_error(PARAMETER_PROBLEM,
-							   "u32: at char %d expected , or &&", arg-start);
-					arg++;
-				}
-				data->tests[testind].value[valind].min = parse_number(&arg, arg-start);
-				while (isspace(*arg)) 
-					arg++;  /* another place white space could be */
-				if (*arg==':') {
-					arg++;
-					data->tests[testind].value[valind].max
-						= parse_number(&arg, arg-start);
-				}
-				else data->tests[testind].value[valind].max
-					     = data->tests[testind].value[valind].min;
-				valind++;
-				if (valind > U32MAXSIZE)
-					exit_error(PARAMETER_PROBLEM,
-						   "u32: at char %d too many ,'s", arg-start);
-			}
-		}
+	switch (c) {
+	case '1':
+		if (*flags & OFFSET)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --offset");
+		info->offset = atoi(optarg);
+		*flags |= OFFSET;
+		break;
+	case '2':
+		if (*flags & MASK)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --mask");
+		if (parse_hex(optarg, &info->mask) == -1)
+			exit_error(PARAMETER_PROBLEM,
+				   "Mask must be in hexadecimal: use format xhhxhhxhhxhh where h=[0-f]");
+		*flags |= MASK;
+		break;
+	case '3':
+		if (*flags & VALUE)
+			exit_error(PARAMETER_PROBLEM,
+				   "Can't specify multiple --value");
+		if (parse_hex(optarg, &info->val) == -1)
+			exit_error(PARAMETER_PROBLEM,
+				   "Value must be in hexadecimal: use format xhhxhhxhhxhh where h=[0-f]");
+		*flags |= VALUE;
+		break;
+	default:
+		return 0;
 	}
+	return 1;
 }
 
-/* Final check; must specify something. */
-static void
-final_check(unsigned int flags)
+
+/* Final check; must have specified --offset and --value. */
+static void final_check(unsigned int flags)
 {
+	if (!(flags & OFFSET))
+		exit_error(PARAMETER_PROBLEM,
+			   "U32 match: You must specify `--offset'");
+	if (!(flags & VALUE))
+		exit_error(PARAMETER_PROBLEM,
+			   "U32 match: You must specify `--value'");
 }
 
 /* Prints out the matchinfo. */
-static void
-print(const struct ipt_ip *ip,
-      const struct ipt_entry_match *match,
-      int numeric)
+static void print(const struct ipt_ip *ip,
+		  const struct ipt_entry_match *match,
+		  int numeric)
 {
-	printf("u32 ");
-	print_u32((struct ipt_u32 *)match->data);
+	const struct ipt_u32_info *info =
+	    (const struct ipt_u32_info*) match->data;
+
+	printf("OFFSET %d ", info->offset);
+	printf("MASK %.2x%.2x%.2x%.2x ", (info->mask >> 24) & 0xFF,
+				         (info->mask >> 16) & 0xFF,
+				         (info->mask >> 8) & 0xFF,
+				         (info->mask) & 0xFF);
+	printf("VALUE %.2x%.2x%.2x%.2x ", (info->val >> 24) & 0xFF,
+				          (info->val >> 16) & 0xFF,
+				          (info->val >> 8) & 0xFF,
+				          (info->val) & 0xFF);
 }
 
-/* Saves the union ipt_matchinfo in parsable form to stdout. */
+
+/* Saves the union ipt_matchinfo in parseable form to stdout. */
 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
 {
-	printf("--u32 ");
-	print_u32((struct ipt_u32 *)match->data);
+	const struct ipt_u32_info *info =
+	    (const struct ipt_u32_info*) match->data;
+
+	printf("--offset %d ", info->offset);
+	printf("--mask x%.2xx%.2xx%.2xx%.2x ", (info->mask >> 24) & 0xFF,
+				               (info->mask >> 16) & 0xFF,
+				               (info->mask >> 8)  & 0xFF,
+				               info->mask & 0xFF);
+	printf("--value x%.2xx%.2xx%.2xx%.2x ", (info->val >> 24) & 0xFF,
+				                (info->val >> 16) & 0xFF,
+				                (info->val >> 8) & 0xFF,
+				                info->val & 0xFF);
 }
 
-struct iptables_match u32 = {
-	.next		= NULL,
-	.name		= "u32",
-	.version	= IPTABLES_VERSION,
-	.size		= IPT_ALIGN(sizeof(struct ipt_u32)),
-	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_u32)),
-	.help		= &help,
-	.parse		= &parse,
-	.final_check	= &final_check,
-	.print		= &print,
-	.save		= &save,
-	.extra_opts	= opts
+static struct iptables_match u32 = {
+    .name		= "u32",
+    .version		= IPTABLES_VERSION,
+    .size		= IPT_ALIGN(sizeof(struct ipt_u32_info)),
+    .userspacesize	= IPT_ALIGN(sizeof(struct ipt_u32_info)),
+    .help		= help,
+    .init		= init,
+    .parse		= parse,
+    .final_check	= final_check,
+    .print		= print,
+    .save		= save,
+    .extra_opts		= opts
 };
 
-void
-_init(void)
+void _init(void)
 {
 	register_match(&u32);
 }

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][IPTABLES] userspace u32 match support
  2006-11-10  1:31 [PATCH][IPTABLES] userspace u32 match support Pablo Neira Ayuso
@ 2006-11-15  9:19 ` Krzysztof Oledzki
  2006-11-15  9:35   ` Patrick McHardy
  0 siblings, 1 reply; 4+ messages in thread
From: Krzysztof Oledzki @ 2006-11-15  9:19 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Harald Welte, Michael Rash, Netfilter Development Mailinglist,
	Patrick McHardy

[-- Attachment #1: Type: TEXT/PLAIN, Size: 484 bytes --]



On Fri, 10 Nov 2006, Pablo Neira Ayuso wrote:

> Add support for u32 match in userspace

Thanks, but the original u32 match was much more powerful and allowed for 
example to move to a next header (ip->tcp) using the @ operator and 
generally to build more advanced test. As you used the same name (u32) it 
will be no longer possible to use the old one.

So, are there any plans to implement full power of the old u32 extension?

Best regards,

 			Krzysztof Olędzki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][IPTABLES] userspace u32 match support
  2006-11-15  9:19 ` Krzysztof Oledzki
@ 2006-11-15  9:35   ` Patrick McHardy
  2006-11-15 12:53     ` Pablo Neira Ayuso
  0 siblings, 1 reply; 4+ messages in thread
From: Patrick McHardy @ 2006-11-15  9:35 UTC (permalink / raw)
  To: Krzysztof Oledzki
  Cc: Harald Welte, Michael Rash, Netfilter Development Mailinglist,
	Pablo Neira Ayuso

Krzysztof Oledzki wrote:
> On Fri, 10 Nov 2006, Pablo Neira Ayuso wrote:
> 
>> Add support for u32 match in userspace
> 
> 
> Thanks, but the original u32 match was much more powerful and allowed
> for example to move to a next header (ip->tcp) using the @ operator and
> generally to build more advanced test. As you used the same name (u32)
> it will be no longer possible to use the old one.

Yes, this is a problem. Without beeing able to get at the TCP
header or data it is of much less use.

> So, are there any plans to implement full power of the old u32 extension?

I agree, we should integrate the original version.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH][IPTABLES] userspace u32 match support
  2006-11-15  9:35   ` Patrick McHardy
@ 2006-11-15 12:53     ` Pablo Neira Ayuso
  0 siblings, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2006-11-15 12:53 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Harald Welte, Michael Rash, Netfilter Development Mailinglist

Patrick McHardy wrote:
> Krzysztof Oledzki wrote:
>> On Fri, 10 Nov 2006, Pablo Neira Ayuso wrote:
>>
>>> Add support for u32 match in userspace
>>
>> Thanks, but the original u32 match was much more powerful and allowed
>> for example to move to a next header (ip->tcp) using the @ operator and
>> generally to build more advanced test. As you used the same name (u32)
>> it will be no longer possible to use the old one.
> 
> Yes, this is a problem. Without beeing able to get at the TCP
> header or data it is of much less use.
> 
>> So, are there any plans to implement full power of the old u32 extension?
> 
> I agree, we should integrate the original version.

OK, I'll give another spin to this issue.

-- 
The dawn of the fourth age of Linux firewalling is coming; a time of 
great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-11-15 12:53 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-10  1:31 [PATCH][IPTABLES] userspace u32 match support Pablo Neira Ayuso
2006-11-15  9:19 ` Krzysztof Oledzki
2006-11-15  9:35   ` Patrick McHardy
2006-11-15 12:53     ` Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.