* xt_u32 kernel 20070620
@ 2007-06-19 22:39 Jan Engelhardt
2007-06-19 22:39 ` xt_u32 iptables 20070620 Jan Engelhardt
2007-06-20 9:56 ` xt_u32 kernel 20070620 Pablo Neira Ayuso
0 siblings, 2 replies; 9+ messages in thread
From: Jan Engelhardt @ 2007-06-19 22:39 UTC (permalink / raw)
To: kaber; +Cc: Netfilter Developer Mailing List
[-- Attachment #1: Type: TEXT/PLAIN, Size: 7039 bytes --]
Subject: Add the U32 match from POM-NG
Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
Plus ipv6 support, kmalloc the buffer, inversion support.
Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
---
include/linux/netfilter/xt_u32.h | 40 ++++++++++
net/netfilter/Kconfig | 13 +++
net/netfilter/Makefile | 1
net/netfilter/xt_u32.c | 148 +++++++++++++++++++++++++++++++++++++++
4 files changed, 202 insertions(+)
Index: linux-2.6.22-rc4/include/linux/netfilter/xt_u32.h
===================================================================
--- /dev/null
+++ linux-2.6.22-rc4/include/linux/netfilter/xt_u32.h
@@ -0,0 +1,40 @@
+#ifndef _XT_U32_H
+#define _XT_U32_H 1
+
+enum xt_u32_ops {
+ XT_U32_AND,
+ XT_U32_LEFTSH,
+ XT_U32_RIGHTSH,
+ XT_U32_AT,
+};
+
+struct xt_u32_location_element {
+ u_int32_t number;
+ u_int8_t nextop;
+};
+
+struct xt_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 with a limit of 10 each.
+ */
+#define XT_U32_MAXSIZE 10
+
+struct xt_u32_test {
+ struct xt_u32_location_element location[XT_U32_MAXSIZE+1];
+ struct xt_u32_value_element value[XT_U32_MAXSIZE+1];
+ u_int8_t nnums;
+ u_int8_t nvalues;
+};
+
+struct xt_u32 {
+ struct xt_u32_test tests[XT_U32_MAXSIZE+1];
+ u_int8_t ntests;
+ u_int8_t invert;
+};
+
+#endif /* _XT_U32_H */
Index: linux-2.6.22-rc4/net/netfilter/Kconfig
===================================================================
--- linux-2.6.22-rc4.orig/net/netfilter/Kconfig
+++ linux-2.6.22-rc4/net/netfilter/Kconfig
@@ -635,6 +635,19 @@ config NETFILTER_XT_MATCH_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_U32
+ tristate '"u32" match support'
+ depends on NETFILTER_XTABLES
+ ---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.
+
config NETFILTER_XT_MATCH_HASHLIMIT
tristate '"hashlimit" match support'
depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
Index: linux-2.6.22-rc4/net/netfilter/Makefile
===================================================================
--- linux-2.6.22-rc4.orig/net/netfilter/Makefile
+++ linux-2.6.22-rc4/net/netfilter/Makefile
@@ -72,4 +72,5 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTI
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
Index: linux-2.6.22-rc4/net/netfilter/xt_u32.c
===================================================================
--- /dev/null
+++ linux-2.6.22-rc4/net/netfilter/xt_u32.c
@@ -0,0 +1,148 @@
+/*
+ * xt_u32 - kernel module to match u32 packet content
+ *
+ * Original author: Don Cohen <don@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_u32.h>
+
+#define XT_U32_BUFFER_SIZE (64 * 1024)
+
+/* This is slow, but it's simple. --RR */
+
+static DEFINE_SPINLOCK(u32_lock);
+static char *u32_buffer;
+
+static bool u32_match_it(const struct xt_u32 *data,
+ const struct sk_buff *skb)
+{
+ const struct xt_u32_test *ct;
+ const unsigned char *base;
+ const unsigned char *head;
+ unsigned int testind;
+ unsigned int nnums;
+ unsigned int nvals;
+ unsigned int i;
+ u_int32_t pos;
+ u_int32_t val;
+ u_int32_t at;
+
+ base = head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
+ BUG_ON(head == NULL);
+
+ /*
+ * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17"
+ * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands.
+ */
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+ at = 0;
+ pos = ct->location[0].number;
+
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ val = (base[pos] << 24) | (base[pos+1] << 16) |
+ (base[pos+2] << 8) | base[pos+3];
+ nnums = ct->nnums;
+
+ /* Inner loop runs over "&", "<<", ">>" and "@" operands */
+ for (i = 1; i < nnums; ++i) {
+ u_int32_t number = ct->location[i].number;
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ val &= number;
+ break;
+ case XT_U32_LEFTSH:
+ val <<= number;
+ break;
+ case XT_U32_RIGHTSH:
+ val >>= number;
+ break;
+ case XT_U32_AT:
+ at += val;
+ pos = number;
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ val = (base[at+pos] << 24) |
+ (base[at+pos+1] << 16) |
+ (base[at+pos+2] << 8) | base[at+pos+3];
+ break;
+ }
+ }
+
+ /* Run over the "," and ":" operands */
+ nvals = ct->nvalues;
+ for (i = 0; i < nvals; ++i)
+ if (ct->value[i].min <= val && val <= ct->value[i].max)
+ break;
+
+ if (i >= ct->nvalues)
+ return false;
+ }
+
+ return true;
+}
+
+static bool u32_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_u32 *data = matchinfo;
+ bool ret;
+
+ spin_lock_bh(&u32_lock);
+ ret = u32_match_it(data, skb);
+ spin_unlock_bh(&u32_lock);
+
+ return ret ^ data->invert;
+}
+
+static struct xt_match u32_reg[] = {
+ {
+ .name = "u32",
+ .family = AF_INET,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "u32",
+ .family = AF_INET6,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_u32_init(void)
+{
+ u32_buffer = kmalloc(XT_U32_BUFFER_SIZE, GFP_KERNEL);
+ if (u32_buffer == NULL)
+ return -ENOMEM;
+ return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+static void __exit xt_u32_exit(void)
+{
+ xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
+ kfree(u32_buffer);
+}
+
+module_init(xt_u32_init);
+module_exit(xt_u32_exit);
+MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
+MODULE_DESCRIPTION("netfilter u32 match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_u32");
+MODULE_ALIAS("ip6t_u32");
^ permalink raw reply [flat|nested] 9+ messages in thread
* xt_u32 iptables 20070620
2007-06-19 22:39 xt_u32 kernel 20070620 Jan Engelhardt
@ 2007-06-19 22:39 ` Jan Engelhardt
2007-06-20 9:56 ` xt_u32 kernel 20070620 Pablo Neira Ayuso
1 sibling, 0 replies; 9+ messages in thread
From: Jan Engelhardt @ 2007-06-19 22:39 UTC (permalink / raw)
To: kaber; +Cc: Netfilter Developer Mailing List
[-- Attachment #1: Type: TEXT/PLAIN, Size: 22598 bytes --]
u32 patch for iptables.
Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
---
symlink extensions/.u32-test6 -> extensions/.u32-test
symlink extensions/libip6t_u32.man -> extensions/libipt_u32.man
extensions/.u32-test | 2
extensions/libip6t_u32.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++
extensions/libipt_u32.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++
extensions/libipt_u32.man | 129 ++++++++++++++++++++
4 files changed, 713 insertions(+)
Index: iptables/extensions/.u32-test
===================================================================
--- /dev/null
+++ iptables/extensions/.u32-test
@@ -0,0 +1,2 @@
+#!/bin/sh
+[ -f "$KERNEL_DIR/include/linux/netfilter/xt_u32.h" ] && echo u32
Index: iptables/extensions/libip6t_u32.c
===================================================================
--- /dev/null
+++ iptables/extensions/libip6t_u32.c
@@ -0,0 +1,291 @@
+/* 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/netfilter/xt_u32.c
+ *
+ * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ * Released under the terms of GNU GPL v2
+ */
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ip6tables.h>
+#include <linux/netfilter/xt_u32.h>
+
+static const struct option u32_opts[] = {
+ {"u32", 1, NULL, '1'},
+ {NULL},
+};
+
+/* Function which prints out usage message. */
+static void u32_help(void)
+{
+ printf(
+ "u32 v%s options:\n"
+ "[!] --u32 tests\n"
+ "\t\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
+ "\t\t\t""value := range | value \",\" range\n"
+ "\t\t\t""range := number | number \":\" number\n"
+ "\t\t\t""location := number | location operator number\n"
+ "\t\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n",
+ IPTABLES_VERSION);
+ return;
+}
+
+/* shared printing code */
+static void u32_dump(const struct xt_u32 *data)
+{
+ const struct xt_u32_test *ct;
+ unsigned int testind, i;
+
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+
+ if (testind > 0)
+ printf("&&");
+
+ printf("0x%x", ct->location[0].number);
+ for (i = 1; i < ct->nnums; ++i) {
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ printf("&");
+ break;
+ case XT_U32_LEFTSH:
+ printf("<<");
+ break;
+ case XT_U32_RIGHTSH:
+ printf(">>");
+ break;
+ case XT_U32_AT:
+ printf("@");
+ break;
+ }
+ printf("0x%x", ct->location[i].number);
+ }
+
+ printf("=");
+ for (i = 0; i < ct->nvalues; ++i) {
+ if (i > 0)
+ printf(",");
+ if (ct->value[i].min == ct->value[i].max)
+ printf("0x%x", ct->value[i].min);
+ else
+ printf("0x%x:0x%x", ct->value[i].min,
+ ct->value[i].max);
+ }
+ }
+ printf(" ");
+}
+
+/* string_to_number is not quite what we need here ... */
+static uint32_t parse_number(char **s, int pos)
+{
+ uint32_t number;
+ char *end;
+ errno = 0;
+
+ 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;
+}
+
+/* Function which parses command options; returns true if it ate an option */
+static int u32_parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ip6t_entry *entry, unsigned int *nfcache,
+ struct ip6t_entry_match **match)
+{
+ struct xt_u32 *data = (void *)(*match)->data;
+ unsigned int testind = 0, locind = 0, valind = 0;
+ struct xt_u32_test *ct = &data->tests[testind]; /* current test */
+ char *arg = argv[optind-1]; /* the argument string */
+ char *start = arg;
+ int state = 0;
+
+ if (c != '1')
+ return 0;
+
+ data->invert = invert;
+
+ /*
+ * states:
+ * 0 = looking for numbers and operations,
+ * 1 = looking for ranges
+ */
+ while (1) {
+ /* read next operand/number or range */
+ while (isspace(*arg))
+ ++arg;
+
+ if (*arg == '\0') {
+ /* 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");
+
+ ct->nnums = locind;
+ ct->nvalues = valind;
+ data->ntests = ++testind;
+
+ if (testind > XT_U32_MAXSIZE)
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: too many \"&&\"s",
+ arg - start);
+ 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 != 0) {
+ /* need op before number */
+ if (*arg == '&') {
+ ct->location[locind].nextop = XT_U32_AND;
+ } else if (*arg == '<') {
+ if (*++arg != '<')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second < expected", arg - start);
+ ct->location[locind].nextop = XT_U32_LEFTSH;
+ } else if (*arg == '>') {
+ if (*++arg != '>')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second > expected", arg - start);
+ ct->location[locind].nextop = XT_U32_RIGHTSH;
+ } else if (*arg == '@') {
+ ct->location[locind].nextop = XT_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? */
+ ct->location[locind].number =
+ parse_number(&arg, arg - start);
+ if (++locind > XT_U32_MAXSIZE)
+ 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 == '&') {
+ if (*++arg != '&')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second & was expected", arg - start);
+ if (valind == 0) {
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: value spec missing", arg - start);
+ } else {
+ ct->nnums = locind;
+ ct->nvalues = valind;
+ ct = &data->tests[++testind];
+ if (testind > XT_U32_MAXSIZE)
+ 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 > 0) { /* need , before number */
+ if (*arg != ',')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: expected , or &&", arg - start);
+ ++arg;
+ }
+ ct->value[valind].min =
+ parse_number(&arg, arg - start);
+
+ while (isspace(*arg))
+ ++arg;
+
+ if (*arg == ':') {
+ ++arg;
+ ct->value[valind].max =
+ parse_number(&arg, arg-start);
+ } else {
+ ct->value[valind].max =
+ ct->value[valind].min;
+ }
+
+ if (++valind > XT_U32_MAXSIZE)
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: too many \",\"s", arg - start);
+ }
+ }
+ }
+}
+
+/* Final check; must specify something. */
+static void u32_final_check(unsigned int flags)
+{
+}
+
+/* Prints out the matchinfo. */
+static void u32_print(const struct ip6t_ip6 *ip,
+ const struct ip6t_entry_match *match, int numeric)
+{
+ printf("u32 ");
+ u32_dump((const void *)match->data);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void u32_save(const struct ip6t_ip6 *ip,
+ const struct ip6t_entry_match *match)
+{
+ printf("--u32 ");
+ u32_dump((const void *)match->data);
+}
+
+static struct ip6tables_match u32_reg = {
+ .name = "u32",
+ .version = IPTABLES_VERSION,
+ .size = IP6T_ALIGN(sizeof(struct xt_u32)),
+ .userspacesize = IP6T_ALIGN(sizeof(struct xt_u32)),
+ .help = u32_help,
+ .parse = u32_parse,
+ .final_check = u32_final_check,
+ .print = u32_print,
+ .save = u32_save,
+ .extra_opts = u32_opts,
+};
+
+static __attribute__((constructor)) void libip6t_u32_init(void)
+{
+ register_match6(&u32_reg);
+ return;
+}
Index: iptables/extensions/libipt_u32.c
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_u32.c
@@ -0,0 +1,291 @@
+/* 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/netfilter/xt_u32.c
+ *
+ * (C) 2002 by Don Cohen <don-netf@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ * Released under the terms of GNU GPL v2
+ */
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <iptables.h>
+#include <linux/netfilter/xt_u32.h>
+
+static const struct option u32_opts[] = {
+ {"u32", 1, NULL, '1'},
+ {NULL},
+};
+
+/* Function which prints out usage message. */
+static void u32_help(void)
+{
+ printf(
+ "u32 v%s options:\n"
+ "[!] --u32 tests\n"
+ "\t\t\t""tests := location \"=\" value | tests \"&&\" location \"=\" value\n"
+ "\t\t\t""value := range | value \",\" range\n"
+ "\t\t\t""range := number | number \":\" number\n"
+ "\t\t\t""location := number | location operator number\n"
+ "\t\t\t""operator := \"&\" | \"<<\" | \">>\" | \"@\"\n",
+ IPTABLES_VERSION);
+ return;
+}
+
+/* shared printing code */
+static void u32_dump(const struct xt_u32 *data)
+{
+ const struct xt_u32_test *ct;
+ unsigned int testind, i;
+
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+
+ if (testind > 0)
+ printf("&&");
+
+ printf("0x%x", ct->location[0].number);
+ for (i = 1; i < ct->nnums; ++i) {
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ printf("&");
+ break;
+ case XT_U32_LEFTSH:
+ printf("<<");
+ break;
+ case XT_U32_RIGHTSH:
+ printf(">>");
+ break;
+ case XT_U32_AT:
+ printf("@");
+ break;
+ }
+ printf("0x%x", ct->location[i].number);
+ }
+
+ printf("=");
+ for (i = 0; i < ct->nvalues; ++i) {
+ if (i > 0)
+ printf(",");
+ if (ct->value[i].min == ct->value[i].max)
+ printf("0x%x", ct->value[i].min);
+ else
+ printf("0x%x:0x%x", ct->value[i].min,
+ ct->value[i].max);
+ }
+ }
+ printf(" ");
+}
+
+/* string_to_number is not quite what we need here ... */
+static uint32_t parse_number(char **s, int pos)
+{
+ uint32_t number;
+ char *end;
+ errno = 0;
+
+ 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;
+}
+
+/* Function which parses command options; returns true if it ate an option */
+static int u32_parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry, unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct xt_u32 *data = (void *)(*match)->data;
+ unsigned int testind = 0, locind = 0, valind = 0;
+ struct xt_u32_test *ct = &data->tests[testind]; /* current test */
+ char *arg = argv[optind-1]; /* the argument string */
+ char *start = arg;
+ int state = 0;
+
+ if (c != '1')
+ return 0;
+
+ data->invert = invert;
+
+ /*
+ * states:
+ * 0 = looking for numbers and operations,
+ * 1 = looking for ranges
+ */
+ while (1) {
+ /* read next operand/number or range */
+ while (isspace(*arg))
+ ++arg;
+
+ if (*arg == '\0') {
+ /* 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");
+
+ ct->nnums = locind;
+ ct->nvalues = valind;
+ data->ntests = ++testind;
+
+ if (testind > XT_U32_MAXSIZE)
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: too many \"&&\"s",
+ arg - start);
+ 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 != 0) {
+ /* need op before number */
+ if (*arg == '&') {
+ ct->location[locind].nextop = XT_U32_AND;
+ } else if (*arg == '<') {
+ if (*++arg != '<')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second < expected", arg - start);
+ ct->location[locind].nextop = XT_U32_LEFTSH;
+ } else if (*arg == '>') {
+ if (*++arg != '>')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second > expected", arg - start);
+ ct->location[locind].nextop = XT_U32_RIGHTSH;
+ } else if (*arg == '@') {
+ ct->location[locind].nextop = XT_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? */
+ ct->location[locind].number =
+ parse_number(&arg, arg - start);
+ if (++locind > XT_U32_MAXSIZE)
+ 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 == '&') {
+ if (*++arg != '&')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: a second & was expected", arg - start);
+ if (valind == 0) {
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: value spec missing", arg - start);
+ } else {
+ ct->nnums = locind;
+ ct->nvalues = valind;
+ ct = &data->tests[++testind];
+ if (testind > XT_U32_MAXSIZE)
+ 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 > 0) { /* need , before number */
+ if (*arg != ',')
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: expected , or &&", arg - start);
+ ++arg;
+ }
+ ct->value[valind].min =
+ parse_number(&arg, arg - start);
+
+ while (isspace(*arg))
+ ++arg;
+
+ if (*arg == ':') {
+ ++arg;
+ ct->value[valind].max =
+ parse_number(&arg, arg-start);
+ } else {
+ ct->value[valind].max =
+ ct->value[valind].min;
+ }
+
+ if (++valind > XT_U32_MAXSIZE)
+ exit_error(PARAMETER_PROBLEM,
+ "u32: at char %d: too many \",\"s", arg - start);
+ }
+ }
+ }
+}
+
+/* Final check; must specify something. */
+static void u32_final_check(unsigned int flags)
+{
+}
+
+/* Prints out the matchinfo. */
+static void u32_print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match, int numeric)
+{
+ printf("u32 ");
+ u32_dump((const void *)match->data);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void u32_save(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match)
+{
+ printf("--u32 ");
+ u32_dump((const void *)match->data);
+}
+
+static struct iptables_match u32_reg = {
+ .name = "u32",
+ .version = IPTABLES_VERSION,
+ .size = IPT_ALIGN(sizeof(struct xt_u32)),
+ .userspacesize = IPT_ALIGN(sizeof(struct xt_u32)),
+ .help = u32_help,
+ .parse = u32_parse,
+ .final_check = u32_final_check,
+ .print = u32_print,
+ .save = u32_save,
+ .extra_opts = u32_opts,
+};
+
+static __attribute__((constructor)) void libipt_u32_init(void)
+{
+ register_match(&u32_reg);
+ return;
+}
Index: iptables/extensions/libipt_u32.man
===================================================================
--- /dev/null
+++ iptables/extensions/libipt_u32.man
@@ -0,0 +1,129 @@
+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.
+.TP
+[\fB!\fR]\fB --u32 \fItests\fR
+The argument amounts to a program in a small language described below.
+.IP
+tests := location "=" value | tests "&&" location "=" value
+.IP
+value := range | value "," range
+.IP
+range := number | number ":" number
+.PP
+a single number, \fIn\fR, is interpreted the same as \fIn:n\fR. \fIn:m\fR is
+interpreted as the range of numbers \fB>=n\fR and \fB<=m\fR.
+.IP "" 4
+location := number | location operator number
+.IP "" 4
+operator := "&" | "<<" | ">>" | "@"
+.PP
+The operators \fB&\fR, \fB<<\fR, \fB>>\fR and \fB&&\fR mean the same as in C.
+The \fB=\fR is really a set membership operator and the value syntax describes
+a set. The \fB@\fR operator is what allows moving to the next header and is
+described further below.
+.PP
+There are currently some artificial implementation limits on the size of the
+tests:
+.IP " *"
+no more than 10 of "\fB=\fR" (and 9 "\fB&&\fR"s) in the u32 argument
+.IP " *"
+no more than 10 ranges (and 9 commas) per value
+.IP " *"
+no more than 10 numbers (and 9 operators) per location
+.PP
+To describe the meaning of location, imagine the following machine that
+interprets it. There are three registers:
+.IP
+A is of type \fBchar *\fR, initially the address of the IP header
+.IP
+B and C are unsigned 32 bit integers, initially zero
+.PP
+The instructions are:
+.IP
+number B = number;
+.IP
+C = (*(A+B)<<24) + (*(A+B+1)<<16) + (*(A+B+2)<<8) + *(A+B+3)
+.IP
+&number C = C & number
+.IP
+<< number C = C << number
+.IP
+>> number C = C >> number
+.IP
+@number A = A + C; then do the instruction number
+.PP
+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.
+.PP
+Whitespace is allowed but not required in the tests. However, the characters
+that do occur there are likely to require shell quoting, so it is a good idea
+to enclose the arguments in quotes.
+.PP
+Example:
+.IP
+match IP packets with total length >= 256
+.IP
+The IP header contains a total length field in bytes 2-3.
+.IP
+--u32 "\fB0 & 0xFFFF = 0x100:0xFFFF\fR"
+.IP
+read bytes 0-3
+.IP
+AND that with 0xFFFF (giving bytes 2-3), and test whether that is in the range
+[0x100:0xFFFF]
+.PP
+Example: (more realistic, hence more complicated)
+.IP
+match ICMP packets with icmp type 0
+.IP
+First test that it is an ICMP packet, true iff byte 9 (protocol) = 1
+.IP
+--u32 "\fB6 & 0xFF = 1 &&\fR ...
+.IP
+read bytes 6-9, use \fB&\fR to throw away bytes 6-8 and compare the result to
+1. Next test that it is not a fragment. (If so, it might be part of such a
+packet but we cannot 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.
+.IP
+ ... \fB4 & 0x3FFF = 0 &&\fR ...
+.IP
+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.
+.IP
+ ... \fB0 >> 22 & 0x3C @ 0 >> 24 = 0\fR"
+.IP
+The first 0 means read bytes 0-3, \fB>>22\fR 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. \fB&3C\fR 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, \fB>>22\fR gives the 10 bit value xxxx0101yy and
+\fB&3C\fR gives 010100. \fB@\fR 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.
+.PP
+Example:
+.IP
+TCP payload bytes 8-12 is any of 1, 2, 5 or 8
+.IP
+First we test that the packet is a tcp packet (similar to ICMP).
+.IP
+--u32 "\fB6 & 0xFF = 6 &&\fR ...
+.IP
+Next, test that it is not a fragment (same as above).
+.IP
+ ... \fB0 >> 22 & 0x3C @ 12 >> 26 & 0x3C @ 8 = 1,2,5,8\fR"
+.IP
+\fB0>>22&3C\fR as above computes the number of bytes in the IP header. \fB@\fR
+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 \fB12>>26&3C\fR 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
+\fB=\fR checks whether the result is any of 1, 2, 5 or 8.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: xt_u32 kernel 20070620
2007-06-19 22:39 xt_u32 kernel 20070620 Jan Engelhardt
2007-06-19 22:39 ` xt_u32 iptables 20070620 Jan Engelhardt
@ 2007-06-20 9:56 ` Pablo Neira Ayuso
2007-06-20 10:43 ` xt_u32 kernel 20070620_2 Jan Engelhardt
1 sibling, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2007-06-20 9:56 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Netfilter Developer Mailing List, kaber
Jan Engelhardt wrote:
> + base = head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
Since we calculate the offset and just take chunks of 32 bits. Why not
use skb_copy_bits instead and copy 4 bytes to a small buffer allocated
in the stack? This would remove the big buffer requirement.
--
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] 9+ messages in thread
* xt_u32 kernel 20070620_2
2007-06-20 9:56 ` xt_u32 kernel 20070620 Pablo Neira Ayuso
@ 2007-06-20 10:43 ` Jan Engelhardt
2007-06-20 11:05 ` Pablo Neira Ayuso
0 siblings, 1 reply; 9+ messages in thread
From: Jan Engelhardt @ 2007-06-20 10:43 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Developer Mailing List, kaber
[-- Attachment #1: Type: TEXT/PLAIN, Size: 7786 bytes --]
On Jun 20 2007 11:56, Pablo Neira Ayuso wrote:
>
> Jan Engelhardt wrote:
>> + base = head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
>
> Since we calculate the offset and just take chunks of 32 bits. Why not use
> skb_copy_bits instead and copy 4 bytes to a small buffer allocated in the
> stack? This would remove the big buffer requirement.
Much more than that, it would actually make xt_u32 truly SMP-"capable" (you
name it), because now there is no buffer that would need to be locked.
Patch below.
Thanks!
Subject: Add the U32 match from POM-NG
Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
Plus:
* 2007-06-02: added ipv6 support
* 2007-06-05: uses kmalloc for the big buffer
* 2007-06-05: added inversion
* 2007-06-20: use skb_copy_bits() and get rid of the big buffer
and lock (suggested by Pablo Neira Ayuso)
Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
---
include/linux/netfilter/xt_u32.h | 40 ++++++++++
net/netfilter/Kconfig | 13 +++
net/netfilter/Makefile | 1
net/netfilter/xt_u32.c | 148 +++++++++++++++++++++++++++++++++++++++
4 files changed, 202 insertions(+)
Index: linux-2.6.22-rc4/include/linux/netfilter/xt_u32.h
===================================================================
--- /dev/null
+++ linux-2.6.22-rc4/include/linux/netfilter/xt_u32.h
@@ -0,0 +1,40 @@
+#ifndef _XT_U32_H
+#define _XT_U32_H 1
+
+enum xt_u32_ops {
+ XT_U32_AND,
+ XT_U32_LEFTSH,
+ XT_U32_RIGHTSH,
+ XT_U32_AT,
+};
+
+struct xt_u32_location_element {
+ u_int32_t number;
+ u_int8_t nextop;
+};
+
+struct xt_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 with a limit of 10 each.
+ */
+#define XT_U32_MAXSIZE 10
+
+struct xt_u32_test {
+ struct xt_u32_location_element location[XT_U32_MAXSIZE+1];
+ struct xt_u32_value_element value[XT_U32_MAXSIZE+1];
+ u_int8_t nnums;
+ u_int8_t nvalues;
+};
+
+struct xt_u32 {
+ struct xt_u32_test tests[XT_U32_MAXSIZE+1];
+ u_int8_t ntests;
+ u_int8_t invert;
+};
+
+#endif /* _XT_U32_H */
Index: linux-2.6.22-rc4/net/netfilter/Kconfig
===================================================================
--- linux-2.6.22-rc4.orig/net/netfilter/Kconfig
+++ linux-2.6.22-rc4/net/netfilter/Kconfig
@@ -635,6 +635,19 @@ config NETFILTER_XT_MATCH_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_U32
+ tristate '"u32" match support'
+ depends on NETFILTER_XTABLES
+ ---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.
+
config NETFILTER_XT_MATCH_HASHLIMIT
tristate '"hashlimit" match support'
depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
Index: linux-2.6.22-rc4/net/netfilter/Makefile
===================================================================
--- linux-2.6.22-rc4.orig/net/netfilter/Makefile
+++ linux-2.6.22-rc4/net/netfilter/Makefile
@@ -72,4 +72,5 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTI
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
Index: linux-2.6.22-rc4/net/netfilter/xt_u32.c
===================================================================
--- /dev/null
+++ linux-2.6.22-rc4/net/netfilter/xt_u32.c
@@ -0,0 +1,148 @@
+/*
+ * xt_u32 - kernel module to match u32 packet content
+ *
+ * Original author: Don Cohen <don@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_u32.h>
+
+#define XT_U32_BUFFER_SIZE (64 * 1024)
+
+/* This is slow, but it's simple. --RR */
+
+static DEFINE_SPINLOCK(u32_lock);
+static char *u32_buffer;
+
+static bool u32_match_it(const struct xt_u32 *data,
+ const struct sk_buff *skb)
+{
+ const struct xt_u32_test *ct;
+ const unsigned char *base;
+ const unsigned char *head;
+ unsigned int testind;
+ unsigned int nnums;
+ unsigned int nvals;
+ unsigned int i;
+ u_int32_t pos;
+ u_int32_t val;
+ u_int32_t at;
+
+ base = head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
+ BUG_ON(head == NULL);
+
+ /*
+ * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17"
+ * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands.
+ */
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+ at = 0;
+ pos = ct->location[0].number;
+
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ val = (base[pos] << 24) | (base[pos+1] << 16) |
+ (base[pos+2] << 8) | base[pos+3];
+ nnums = ct->nnums;
+
+ /* Inner loop runs over "&", "<<", ">>" and "@" operands */
+ for (i = 1; i < nnums; ++i) {
+ u_int32_t number = ct->location[i].number;
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ val &= number;
+ break;
+ case XT_U32_LEFTSH:
+ val <<= number;
+ break;
+ case XT_U32_RIGHTSH:
+ val >>= number;
+ break;
+ case XT_U32_AT:
+ at += val;
+ pos = number;
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ val = (base[at+pos] << 24) |
+ (base[at+pos+1] << 16) |
+ (base[at+pos+2] << 8) | base[at+pos+3];
+ break;
+ }
+ }
+
+ /* Run over the "," and ":" operands */
+ nvals = ct->nvalues;
+ for (i = 0; i < nvals; ++i)
+ if (ct->value[i].min <= val && val <= ct->value[i].max)
+ break;
+
+ if (i >= ct->nvalues)
+ return false;
+ }
+
+ return true;
+}
+
+static bool u32_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_u32 *data = matchinfo;
+ bool ret;
+
+ spin_lock_bh(&u32_lock);
+ ret = u32_match_it(data, skb);
+ spin_unlock_bh(&u32_lock);
+
+ return ret ^ data->invert;
+}
+
+static struct xt_match u32_reg[] = {
+ {
+ .name = "u32",
+ .family = AF_INET,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "u32",
+ .family = AF_INET6,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_u32_init(void)
+{
+ u32_buffer = kmalloc(XT_U32_BUFFER_SIZE, GFP_KERNEL);
+ if (u32_buffer == NULL)
+ return -ENOMEM;
+ return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+static void __exit xt_u32_exit(void)
+{
+ xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
+ kfree(u32_buffer);
+}
+
+module_init(xt_u32_init);
+module_exit(xt_u32_exit);
+MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
+MODULE_DESCRIPTION("netfilter u32 match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_u32");
+MODULE_ALIAS("ip6t_u32");
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: xt_u32 kernel 20070620_2
2007-06-20 11:05 ` Pablo Neira Ayuso
@ 2007-06-20 10:58 ` Jan Engelhardt
2007-06-20 12:25 ` Patrick McHardy
2007-06-21 11:47 ` Patrick McHardy
0 siblings, 2 replies; 9+ messages in thread
From: Jan Engelhardt @ 2007-06-20 10:58 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Developer Mailing List, kaber
[-- Attachment #1: Type: TEXT/PLAIN, Size: 6817 bytes --]
On Jun 20 2007 13:05, Pablo Neira Ayuso wrote:
>
> Wrong patch? :-)
Wrong host...
===
Subject: Add the U32 match from POM-NG
Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
Plus:
* 2007-06-02: added ipv6 support
* 2007-06-05: uses kmalloc for the big buffer
* 2007-06-05: added inversion
* 2007-06-20: use skb_copy_bits() and get rid of the big buffer
and lock (suggested by Pablo Neira Ayuso)
Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
---
include/linux/netfilter/xt_u32.h | 40 +++++++++++
net/netfilter/Kconfig | 13 +++
net/netfilter/Makefile | 1
net/netfilter/xt_u32.c | 131 +++++++++++++++++++++++++++++++++++++++
4 files changed, 185 insertions(+)
Index: linux-2.6.22/include/linux/netfilter/xt_u32.h
===================================================================
--- /dev/null
+++ linux-2.6.22/include/linux/netfilter/xt_u32.h
@@ -0,0 +1,40 @@
+#ifndef _XT_U32_H
+#define _XT_U32_H 1
+
+enum xt_u32_ops {
+ XT_U32_AND,
+ XT_U32_LEFTSH,
+ XT_U32_RIGHTSH,
+ XT_U32_AT,
+};
+
+struct xt_u32_location_element {
+ u_int32_t number;
+ u_int8_t nextop;
+};
+
+struct xt_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 with a limit of 10 each.
+ */
+#define XT_U32_MAXSIZE 10
+
+struct xt_u32_test {
+ struct xt_u32_location_element location[XT_U32_MAXSIZE+1];
+ struct xt_u32_value_element value[XT_U32_MAXSIZE+1];
+ u_int8_t nnums;
+ u_int8_t nvalues;
+};
+
+struct xt_u32 {
+ struct xt_u32_test tests[XT_U32_MAXSIZE+1];
+ u_int8_t ntests;
+ u_int8_t invert;
+};
+
+#endif /* _XT_U32_H */
Index: linux-2.6.22/net/netfilter/Kconfig
===================================================================
--- linux-2.6.22.orig/net/netfilter/Kconfig
+++ linux-2.6.22/net/netfilter/Kconfig
@@ -635,6 +635,19 @@ config NETFILTER_XT_MATCH_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_U32
+ tristate '"u32" match support'
+ depends on NETFILTER_XTABLES
+ ---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.
+
config NETFILTER_XT_MATCH_HASHLIMIT
tristate '"hashlimit" match support'
depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
Index: linux-2.6.22/net/netfilter/Makefile
===================================================================
--- linux-2.6.22.orig/net/netfilter/Makefile
+++ linux-2.6.22/net/netfilter/Makefile
@@ -72,4 +72,5 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTI
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
Index: linux-2.6.22/net/netfilter/xt_u32.c
===================================================================
--- /dev/null
+++ linux-2.6.22/net/netfilter/xt_u32.c
@@ -0,0 +1,131 @@
+/*
+ * xt_u32 - kernel module to match u32 packet content
+ *
+ * Original author: Don Cohen <don@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_u32.h>
+
+/* This is slow, but it's simple. --RR */
+
+static bool u32_match_it(const struct xt_u32 *data,
+ const struct sk_buff *skb)
+{
+ const struct xt_u32_test *ct;
+ unsigned int testind;
+ unsigned int nnums;
+ unsigned int nvals;
+ unsigned int i;
+ u_int32_t pos;
+ u_int32_t val;
+ u_int32_t at;
+
+ /*
+ * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17"
+ * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands.
+ */
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+ at = 0;
+ pos = ct->location[0].number;
+
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ BUG_ON(skb_copy_bits(skb, pos, &val, sizeof(val)) < 0);
+ val = ntohl(val);
+ nnums = ct->nnums;
+
+ /* Inner loop runs over "&", "<<", ">>" and "@" operands */
+ for (i = 1; i < nnums; ++i) {
+ u_int32_t number = ct->location[i].number;
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ val &= number;
+ break;
+ case XT_U32_LEFTSH:
+ val <<= number;
+ break;
+ case XT_U32_RIGHTSH:
+ val >>= number;
+ break;
+ case XT_U32_AT:
+ at += val;
+ pos = number;
+ if (at + pos + 3 > skb->len || at + pos < 0)
+ return false;
+
+ BUG_ON(skb_copy_bits(skb, at+pos, &val,
+ sizeof(val)) < 0);
+ val = ntohl(val);
+ break;
+ }
+ }
+
+ /* Run over the "," and ":" operands */
+ nvals = ct->nvalues;
+ for (i = 0; i < nvals; ++i)
+ if (ct->value[i].min <= val && val <= ct->value[i].max)
+ break;
+
+ if (i >= ct->nvalues)
+ return false;
+ }
+
+ return true;
+}
+
+static bool u32_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_u32 *data = matchinfo;
+ bool ret;
+
+ ret = u32_match_it(data, skb);
+ return ret ^ data->invert;
+}
+
+static struct xt_match u32_reg[] = {
+ {
+ .name = "u32",
+ .family = AF_INET,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "u32",
+ .family = AF_INET6,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_u32_init(void)
+{
+ return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+static void __exit xt_u32_exit(void)
+{
+ xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+module_init(xt_u32_init);
+module_exit(xt_u32_exit);
+MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
+MODULE_DESCRIPTION("netfilter u32 match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_u32");
+MODULE_ALIAS("ip6t_u32");
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: xt_u32 kernel 20070620_2
2007-06-20 10:43 ` xt_u32 kernel 20070620_2 Jan Engelhardt
@ 2007-06-20 11:05 ` Pablo Neira Ayuso
2007-06-20 10:58 ` Jan Engelhardt
0 siblings, 1 reply; 9+ messages in thread
From: Pablo Neira Ayuso @ 2007-06-20 11:05 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Netfilter Developer Mailing List, kaber
Jan Engelhardt wrote:
> On Jun 20 2007 11:56, Pablo Neira Ayuso wrote:
>> Jan Engelhardt wrote:
>>> + base = head = skb_header_pointer(skb, 0, skb->len, u32_buffer);
>> Since we calculate the offset and just take chunks of 32 bits. Why not use
>> skb_copy_bits instead and copy 4 bytes to a small buffer allocated in the
>> stack? This would remove the big buffer requirement.
>
> Much more than that, it would actually make xt_u32 truly SMP-"capable" (you
> name it), because now there is no buffer that would need to be locked.
>
> Patch below.
Wrong patch? :-)
--
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] 9+ messages in thread
* Re: xt_u32 kernel 20070620_2
2007-06-20 10:58 ` Jan Engelhardt
@ 2007-06-20 12:25 ` Patrick McHardy
2007-06-20 12:36 ` Jan Engelhardt
2007-06-21 11:47 ` Patrick McHardy
1 sibling, 1 reply; 9+ messages in thread
From: Patrick McHardy @ 2007-06-20 12:25 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Netfilter Developer Mailing List, Pablo Neira Ayuso
Jan Engelhardt wrote:
> Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
Looks good, I'll apply it later if Pablo doesn't have more comments.
> +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
This should really be your name I guess. You wrote this version
and Don hasn't been active for years. I can change that before
applying.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: xt_u32 kernel 20070620_2
2007-06-20 12:25 ` Patrick McHardy
@ 2007-06-20 12:36 ` Jan Engelhardt
0 siblings, 0 replies; 9+ messages in thread
From: Jan Engelhardt @ 2007-06-20 12:36 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Netfilter Developer Mailing List, Pablo Neira Ayuso
On Jun 20 2007 14:25, Patrick McHardy wrote:
>Jan Engelhardt wrote:
>> Along comes... xt_u32, a revamped ipt_u32 from POM-NG,
>
>
>Looks good, I'll apply it later if Pablo doesn't have more comments.
>
>> +MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
>
>This should really be your name I guess. You wrote this version
>and Don hasn't been active for years. I can change that before
>applying.
Okie thanks. (Though, here could go the MODULE_MAINTAINER() debate again... ;)
Jan
--
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: xt_u32 kernel 20070620_2
2007-06-20 10:58 ` Jan Engelhardt
2007-06-20 12:25 ` Patrick McHardy
@ 2007-06-21 11:47 ` Patrick McHardy
1 sibling, 0 replies; 9+ messages in thread
From: Patrick McHardy @ 2007-06-21 11:47 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: Netfilter Developer Mailing List, Pablo Neira Ayuso
Jan Engelhardt wrote:
>
> Subject: Add the U32 match from POM-NG
Applied, thanks Jan.
>
> +/* This is slow, but it's simple. --RR */
This comment refers to the buffer, so I've removed it.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2007-06-21 11:47 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-19 22:39 xt_u32 kernel 20070620 Jan Engelhardt
2007-06-19 22:39 ` xt_u32 iptables 20070620 Jan Engelhardt
2007-06-20 9:56 ` xt_u32 kernel 20070620 Pablo Neira Ayuso
2007-06-20 10:43 ` xt_u32 kernel 20070620_2 Jan Engelhardt
2007-06-20 11:05 ` Pablo Neira Ayuso
2007-06-20 10:58 ` Jan Engelhardt
2007-06-20 12:25 ` Patrick McHardy
2007-06-20 12:36 ` Jan Engelhardt
2007-06-21 11:47 ` Patrick McHardy
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.