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

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.