u32 match ported to 2.6 and ipv6
PATCH 1/1 u32 match ported to 2.6 and ipv6
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Here goes, it compiles, haven't tested it. :)
- --
- - xkr47
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
iD8DBQFCW/Z8xyF48ZTvn+4RAuvoAKDQSX9BA5jPd1ezjt4nY+fIy1mDeACaAxco /Ux4xJlDPrVpQ9KQHQN34HM=
=wZ42
-----END PGP SIGNATURE-----
u32/iptables.patch +239 -0
@@ -0,0 +1,239 @@ +diff -Np -ur orig-iptables-1.3.1/extensions/libipt_u32.c iptables-1.3.1/extensions/libipt_u32.c +--- orig-iptables-1.3.1/extensions/libipt_u32.c 2005-03-26 17:32:11.000000000 +0200 ++++ iptables-1.3.1/extensions/libipt_u32.c 2005-04-12 19:11:37.000000000 +0300 +@@ -8,222 +8,19 @@ + * Released under the terms of GNU GPL v2 + */ + #include <stdio.h> +-#include <netdb.h> +-#include <string.h> +-#include <stdlib.h> +-#include <getopt.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) +-{ +- 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); +-} +- +-/* defined in /usr/include/getopt.h maybe in man getopt */ +-static struct option opts[] = { +- { "u32", 1, 0, '1' }, +- { 0 } +-}; +- +-/* shared printing code */ +-static void print_u32(struct ipt_u32 *data) +-{ +- unsigned int testind; +- +- 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(" "); +-} ++#include "libipt_u32_helper.c" + +-/* string_to_number is not quite what we need here ... */ +-u_int32_t parse_number(char **s, int pos) +-{ +- u_int32_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 +-parse(int c, char **argv, int invert, unsigned int *flags, ++parse_v4(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; +- +- 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); +- } +- } +- } +-} +- +-/* Final check; must specify something. */ +-static void +-final_check(unsigned int flags) +-{ ++ struct ipt_u32 *data = (struct ipt_u32 *)(*match)->data; ++ return parse(c, argv, data); + } + + /* Prints out the matchinfo. */ +@@ -250,7 +47,7 @@ + .size = IPT_ALIGN(sizeof(struct ipt_u32)), + .userspacesize = IPT_ALIGN(sizeof(struct ipt_u32)), + .help = &help, +- .parse = &parse, ++ .parse = &parse_v4, + .final_check = &final_check, + .print = &print, + .save = &save,
u32/linux-2.6/include/linux/netfilter_ipv4/ipt_u32.h +40 -0
@@ -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*/
u32/linux-2.6/net/ipv4/netfilter/Makefile.ladd +4 -0
@@ -0,0 +1,4 @@ +obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o + +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o +
u32/linux-2.6/net/ipv4/netfilter/Kconfig.ladd +12 -0
@@ -0,0 +1,12 @@ +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.
u32/linux-2.6/net/ipv4/netfilter/ipt_u32.c +215 -0
215 lines not on this page · raw message
u32/linux-2.6/net/ipv6/netfilter/Makefile.ladd +4 -0
@@ -0,0 +1,4 @@ +obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o + +obj-$(CONFIG_IP6_NF_MATCH_U32) += ip6t_u32.o +
u32/linux-2.6/net/ipv6/netfilter/Kconfig.ladd +15 -0
@@ -0,0 +1,15 @@ +config IP6_NF_MATCH_U32 + tristate 'U32 match support' + depends on IP6_NF_IPTABLES && IP_NF_MATCH_U32 + 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. + + Note: This requires the on the ipv4 equivalent of the u32 + match to be enabled. + + Details and examples are in the kernel module ipv4 source.
u32/linux-2.6/net/ipv6/netfilter/ip6t_u32.c +64 -0
64 lines not on this page · raw message
u32/iptables/extensions/libip6t_u32.c +61 -0
61 lines not on this page · raw message
u32/iptables/extensions/.u32-test6 +4 -0
@@ -0,0 +1,4 @@ +#!/bin/sh +# True if u32 is applied. +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_u32.h -a \ + -f $KERNEL_DIR/net/ipv6/netfilter/ip6t_u32.c ] && echo u32
u32/iptables/extensions/libip6t_u32.man +8 -0
@@ -0,0 +1,8 @@ +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.
u32/iptables/extensions/libipt_u32_helper.c +213 -0
213 lines not on this page · raw message
u32/info +0 -1
@@ -2,4 +2,3 @@ Author: Don Cohen <[email protected]> Status: Tested locally, seems to work. Repository: base -Requires: linux < 2.6.0
Quoted 1 line · Jonas Berlin
Here goes, it compiles, haven't tested it. :)
well, I would really like the author (i.e. you) to test it (at least basic features) before we include it.
Would that be possible?
Signature · 5 lines
- Harald Welte <[email protected]> http://netfilter.org/ ============================================================================ "Fragmentation is like classful addressing -- an interesting early architectural error that shows how much experimentation was going on while IP was being designed." -- Paul Vixie
Quoted 7 lines · Harald Welte
Quoted 1 line · Jonas Berlin
Here goes, it compiles, haven't tested it. :)
well, I would really like the author (i.e. you) to test it (at least basic features) before we include it.
Would that be possible?
ok, i've just finished testing it with the following configuration:
-m u32 --u32 "117&0xFFFF=0x1804"
and it "works for me". It is ipv4 only test, since we don't have ipv6 here. Whole iptables command was following:
iptables -t nat -I PREROUTING -i eth1 -m u32 --u32 "117&0xFFFF=0x1804" -m length --length 200:1000 -p udp -d 192.168.5.255 --dport 138 -j DNAT --to 192.168.0.255
as you can see i'm DNAT'ing to broadcast address , pretty unusual, eh? :)
Signature · 1 line
Anatoly Pugachev