All of lore.kernel.org
 help / color / mirror / Atom feed
* iptables u32 match code for review/testing/...
@ 2002-12-27 18:54 Don Cohen
  2003-01-06 12:57 ` Harald Welte
  2003-01-07 18:53 ` iptables u32 match code for review/testing/ Harald Welte
  0 siblings, 2 replies; 14+ messages in thread
From: Don Cohen @ 2002-12-27 18:54 UTC (permalink / raw)
  To: netfilter-devel


Code below.  Doc is in the code for the kernel module.
I've given up on the comment and multiple argument specs - 
now all the tests are in the same argument.
A few remaining questions are marked with "***" in the code.
I look forward to suggestions/corrections etc.

==== <kernel>include/linux/netfilter_ipv4/ipt_u32.h
#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
};

/* *** What's this about?
   Must fit inside union ipt_matchinfo: 16 bytes */
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*/

==== <kernel>net/ipv4/netfilter/ipt_u32.c
/* 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@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@12>>26&0x3C@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 <asm-i386/timex.h> for timing */

MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
MODULE_DESCRIPTION("IP tables u32 matching module");
MODULE_LICENSE("GPL");

static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *hdr,
      u_int16_t datalen,
      int *hotdrop)
{
  const struct ipt_u32 *data = matchinfo;
  int testind, i;
  unsigned char* origbase = (char*)skb->nh.iph;
  unsigned char* base = origbase;
  unsigned char* head = skb->head;
  unsigned char* end = skb->end;
  int nnums, nvals;
  u_int32_t pos, val;
  /* 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) 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); */
      return 0;}
  }
  /* cycles2 = get_cycles();
     printk("succeeded in %d cycles\n", cycles2-cycles1); */
  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
  = { { NULL, NULL }, "u32", &match, &checkentry, NULL, 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);

==== <iptables-1.2.7a>/extensions/libipt_u32.c
/* 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
*/
#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}
};

/* Initialize the match. */
static void
init(struct ipt_entry_match *m, unsigned int *nfcache)
{
  *nfcache |= NFC_UNKNOWN;
}

/* 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(" ");
}

/* 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 = strtol(*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,
      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)
{
}

/* Prints out the matchinfo. */
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);
}

/* Saves the union ipt_matchinfo in parsable 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);
}

struct iptables_match u32
= { NULL,
    "u32",
    IPTABLES_VERSION,
    IPT_ALIGN(sizeof(struct ipt_u32)),
    IPT_ALIGN(sizeof(struct ipt_u32)),
    &help,
    &init,
    &parse,
    &final_check,
    &print,
    &save,
    opts
};

void
_init(void)
{
	register_match(&u32);
}

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

* Re: iptables u32 match code for review/testing/...
  2002-12-27 18:54 iptables u32 match code for review/testing/ Don Cohen
@ 2003-01-06 12:57 ` Harald Welte
  2003-01-06 17:04   ` Don Cohen
  2003-01-07 18:53 ` iptables u32 match code for review/testing/ Harald Welte
  1 sibling, 1 reply; 14+ messages in thread
From: Harald Welte @ 2003-01-06 12:57 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Fri, Dec 27, 2002 at 10:54:41AM -0800, Don Cohen wrote:
> 
> Code below.  Doc is in the code for the kernel module.

Thanks a lot for your contribution.  I'd like to include it into
patch-o-matic, but one of our basic requirements is to adhere the
CodingStyle of the Linux Kernel.

Could you plaese reformat and resubmit? Thanks

-- 
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
"If this were a dictatorship, it'd be a heck of a lot easier, just so long
 as I'm the dictator."  --  George W. Bush Dec 18, 2000

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match code for review/testing/...
  2003-01-06 12:57 ` Harald Welte
@ 2003-01-06 17:04   ` Don Cohen
  2003-01-07 18:57     ` Harald Welte
  0 siblings, 1 reply; 14+ messages in thread
From: Don Cohen @ 2003-01-06 17:04 UTC (permalink / raw)
  To: Harald Welte; +Cc: netfilter-devel

Harald Welte writes:
 > On Fri, Dec 27, 2002 at 10:54:41AM -0800, Don Cohen wrote:
 > > 
 > > Code below.  Doc is in the code for the kernel module.
 > 
 > Thanks a lot for your contribution.  I'd like to include it into
 > patch-o-matic, but one of our basic requirements is to adhere the
 > CodingStyle of the Linux Kernel.
 > 
 > Could you plaese reformat and resubmit? Thanks

Does that mean you like the content or that you're not willing to
read it until the style is correct?
I was hoping to hear some response to the *** questions.
I was expecting complaints about not yet being in PoM form.

I assume you mean Documentation/CodingStyle.
I was trying to follow it. 
hmm, I do tend to put }'s at the end of a line - fixed below
Was the indentation a problem?  The tabs were all 8 spaces, but
perhaps you want wider indentation?
I try the suggested (c-set-style "K&R") (setq c-basic-offset 8).
(Wow, so much for 80 columns!)
Results below.
Is this what you had in mind?


==== <kernel>include/linux/netfilter_ipv4/ipt_u32.h
#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
};

/* *** What's this about?
   Must fit inside union ipt_matchinfo: 16 bytes */
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*/

==== <kernel>net/ipv4/netfilter/ipt_u32.c
/* 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@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@12>>26&0x3C@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 <asm-i386/timex.h> for timing */

MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
MODULE_DESCRIPTION("IP tables u32 matching module");
MODULE_LICENSE("GPL");

static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      const void *hdr,
      u_int16_t datalen,
      int *hotdrop)
{
	const struct ipt_u32 *data = matchinfo;
	int testind, i;
	unsigned char* origbase = (char*)skb->nh.iph;
	unsigned char* base = origbase;
	unsigned char* head = skb->head;
	unsigned char* end = skb->end;
	int nnums, nvals;
	u_int32_t pos, val;
	/* 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) 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); */
			return 0;
		}
	}
	/* cycles2 = get_cycles();
	   printk("succeeded in %d cycles\n", cycles2-cycles1); */
	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
= { { NULL, NULL }, "u32", &match, &checkentry, NULL, 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);

==== <iptables-1.2.7a>/extensions/libipt_u32.c
/* 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
*/
#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}
};

/* Initialize the match. */
static void
init(struct ipt_entry_match *m, unsigned int *nfcache)
{
	*nfcache |= NFC_UNKNOWN;
}

/* 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(" ");
}

/* 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 = strtol(*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,
      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)
{
}

/* Prints out the matchinfo. */
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);
}

/* Saves the union ipt_matchinfo in parsable 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);
}

struct iptables_match u32
= { NULL,
    "u32",
    IPTABLES_VERSION,
    IPT_ALIGN(sizeof(struct ipt_u32)),
    IPT_ALIGN(sizeof(struct ipt_u32)),
    &help,
    &init,
    &parse,
    &final_check,
    &print,
    &save,
    opts
};

void
_init(void)
{
	register_match(&u32);
}

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

* Re: iptables u32 match code for review/testing/...
  2002-12-27 18:54 iptables u32 match code for review/testing/ Don Cohen
  2003-01-06 12:57 ` Harald Welte
@ 2003-01-07 18:53 ` Harald Welte
  1 sibling, 0 replies; 14+ messages in thread
From: Harald Welte @ 2003-01-07 18:53 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Fri, Dec 27, 2002 at 10:54:41AM -0800, Don Cohen wrote:

Ok, here the comments you requested

> /* *** What's this about?
>    Must fit inside union ipt_matchinfo: 16 bytes */

What do you mean by this? 

> /* *** any way to allow for an arbitrary number of elements?
>    for now I settle for a limit of 10 of each */

no way. At least not with the current kernel/userspace interface :(

-- 
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
"If this were a dictatorship, it'd be a heck of a lot easier, just so long
 as I'm the dictator."  --  George W. Bush Dec 18, 2000

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match code for review/testing/...
  2003-01-06 17:04   ` Don Cohen
@ 2003-01-07 18:57     ` Harald Welte
  2003-01-08  6:41       ` Don Cohen
  0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2003-01-07 18:57 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Mon, Jan 06, 2003 at 09:04:36AM -0800, Don Cohen wrote:
> Does that mean you like the content or that you're not willing to
> read it until the style is correct?

I did read it before.

I like the content (code/implementation/idea of having u32).

The only issue is that it doesn't really fit into the current iptables
architecture. Why?
	- because it is a whole classification engine on it's own
	- because it has an arbitrary [variable] amount of match data
	-

Those issues are not possible to resolve, unfortunately.

> I was hoping to hear some response to the *** questions.

please see my other mail, although the answers will be unsatisfactory.

> I was expecting complaints about not yet being in PoM form.

No, this is the last step.

> I assume you mean Documentation/CodingStyle.

yup.

> hmm, I do tend to put }'s at the end of a line - fixed below
> Was the indentation a problem?  The tabs were all 8 spaces, but
> perhaps you want wider indentation?
no, but look at the structure definitions in your header file.

> I try the suggested (c-set-style "K&R") (setq c-basic-offset 8).
> (Wow, so much for 80 columns!)

indent [or emacs styles] don't solve the problem thoroughly. but they
are an acceptable approximation ;)

Thanks again.
-- 
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
"If this were a dictatorship, it'd be a heck of a lot easier, just so long
 as I'm the dictator."  --  George W. Bush Dec 18, 2000

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match code for review/testing/...
  2003-01-07 18:57     ` Harald Welte
@ 2003-01-08  6:41       ` Don Cohen
  2003-01-08 10:31         ` Roberto Nibali
  2003-01-08 10:56         ` Harald Welte
  0 siblings, 2 replies; 14+ messages in thread
From: Don Cohen @ 2003-01-08  6:41 UTC (permalink / raw)
  To: Harald Welte; +Cc: Don Cohen, netfilter-devel

Harald Welte writes (two separate msgs):
  > /* *** What's this about?
  >    Must fit inside union ipt_matchinfo: 16 bytes */
  What do you mean by this?
That was a comment I found in one of the other match modules
(which I used as a template for this one).
I didn't understand it so I thought I better keep it and flag it.
If you don't know what it's about I guess it's safe to discard it.

  > /* *** any way to allow for an arbitrary number of elements?
  >    for now I settle for a limit of 10 of each */
  no way. At least not with the current kernel/userspace interface :(
Ok, then I'll leave it at 10x10x10 (perhaps a lot of overhead for
a single match?)

 > I like the content (code/implementation/idea of having u32).
 > The only issue is that it doesn't really fit into the current iptables
 > architecture. Why?
 > 	- because it is a whole classification engine on it's own
Why is this bad?  I wrote it to do things I wanted to do but didn't
see how.  I think that's good.  If it subsumes a few others that are
out there, even better.  (But it's almost certainly a lot slower than 
any more specialized match, so they're still useful.)

 > 	- because it has an arbitrary [variable] amount of match data
At the moment, a large fixed amount.  I regard that as a fault of
current iptables, though.

 > Those issues are not possible to resolve, unfortunately.

 ...
 > > Was the indentation a problem?  The tabs were all 8 spaces, but
 > > perhaps you want wider indentation?
 > no, but look at the structure definitions in your header file.
Oops.  The "no" above suggests that you don't mind the narrow
indentation, in which case not only the .h file but the earlier
versions of the .c files were ok except for the few misplaced }'s.

But if you do want wide indentation (and don't mind >80 cols)
then here you go:

====
#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*/

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

* Re: iptables u32 match code for review/testing/...
  2003-01-08  6:41       ` Don Cohen
@ 2003-01-08 10:31         ` Roberto Nibali
  2003-01-08 10:56         ` Harald Welte
  1 sibling, 0 replies; 14+ messages in thread
From: Roberto Nibali @ 2003-01-08 10:31 UTC (permalink / raw)
  To: Don Cohen; +Cc: , Harald Welte, netfilter-devel

>  > I like the content (code/implementation/idea of having u32).
>  > The only issue is that it doesn't really fit into the current iptables
>  > architecture. Why?
>  > 	- because it is a whole classification engine on it's own
> Why is this bad?  I wrote it to do things I wanted to do but didn't
> see how.  I think that's good.  If it subsumes a few others that are
> out there, even better.  (But it's almost certainly a lot slower than 
> any more specialized match, so they're still useful.)

What's wrong with: http://www.cyberus.ca/~hadi/patches/action/ ?
Why couldn't you use some of its code for the classification engine?

> But if you do want wide indentation (and don't mind >80 cols)
> then here you go:

Looks a lot nicer and ledgible to me but I'm not the one in position to 
criticise coding style.

Best regards,
Roberto Nibali, ratz
-- 
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq' | dc

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

* Re: iptables u32 match code for review/testing/...
  2003-01-08  6:41       ` Don Cohen
  2003-01-08 10:31         ` Roberto Nibali
@ 2003-01-08 10:56         ` Harald Welte
  2003-01-08 19:53           ` Don Cohen
  2003-01-08 22:10           ` iptables u32 match patch-o-matic (attempt) Don Cohen
  1 sibling, 2 replies; 14+ messages in thread
From: Harald Welte @ 2003-01-08 10:56 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Tue, Jan 07, 2003 at 10:41:05PM -0800, Don Cohen wrote:
> Harald Welte writes (two separate msgs):
>   > /* *** What's this about?
>   >    Must fit inside union ipt_matchinfo: 16 bytes */
>   What do you mean by this?
>
> That was a comment I found in one of the other match modules
> (which I used as a template for this one).
> I didn't understand it so I thought I better keep it and flag it.
> If you don't know what it's about I guess it's safe to discard it.

Hm. A recursive grep through the kernel doesn't find any occurrance of 
'ipt_matchinfo' at all.

However, most userspace iptables plugins still contain a comment
referring to union ipt_matchinfo.  I think this is a remnant of the very
early days of iptables [which I have missed].  I think it's safe to
forget about it.

>   > /* *** any way to allow for an arbitrary number of elements?
>   >    for now I settle for a limit of 10 of each */
>   no way. At least not with the current kernel/userspace interface :(
> Ok, then I'll leave it at 10x10x10 (perhaps a lot of overhead for
> a single match?)

It also means that every single rule containing the u32 match will
occupy smp_num_cpus*1000*sizeof(your structure) bytes of non-swappable
kernel memory.

>  > I like the content (code/implementation/idea of having u32).
>  > The only issue is that it doesn't really fit into the current iptables
>  > architecture. Why?
>  > 	- because it is a whole classification engine on it's own
> Why is this bad?  I wrote it to do things I wanted to do but didn't
> see how.  I think that's good.  If it subsumes a few others that are
> out there, even better.  (But it's almost certainly a lot slower than 
> any more specialized match, so they're still useful.)

Sorry, I didn't make myself clear.  if u32 is used the right way, it is
way better than lots of the static matches within iptables.  However, it
is more like a replacement of the whole iptables packet matching engine,
than a plugin/extension to it.  Making it a plugin/extension will
unfortunately become a sort-of clumsy approach.   I don't blame or
critisize you... this is not an issue of implementation, but a
fundamental architectural problem.

>  > 	- because it has an arbitrary [variable] amount of match data
> At the moment, a large fixed amount.  I regard that as a fault of
> current iptables, though.

I totally agree.  I said "it doesn't really fit into the current
iptables architecture".  

>  > > Was the indentation a problem?  The tabs were all 8 spaces, but
>  > > perhaps you want wider indentation?
>  > no, but look at the structure definitions in your header file.
> Oops.  The "no" above suggests that you don't mind the narrow
> indentation, in which case not only the .h file but the earlier
> versions of the .c files were ok except for the few misplaced }'s.

I really should work on the precision of my language, it seems.

the indentation was a problem, yes. no, I don't want wider indentation
than 8.

> But if you do want wide indentation (and don't mind >80 cols)
> then here you go:

yes.  If you now would be as friendly to post it as a unified diff
against current patch-o-matic CVS, attached in MIME format?  (And for
posting habits and/or coding style hints there are plenty of examples in
the list archives respectively CVS).

Thanks again.

-- 
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
"If this were a dictatorship, it'd be a heck of a lot easier, just so long
 as I'm the dictator."  --  George W. Bush Dec 18, 2000

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match code for review/testing/...
  2003-01-08 10:56         ` Harald Welte
@ 2003-01-08 19:53           ` Don Cohen
  2003-01-08 21:16             ` Harald Welte
  2003-01-08 22:10           ` iptables u32 match patch-o-matic (attempt) Don Cohen
  1 sibling, 1 reply; 14+ messages in thread
From: Don Cohen @ 2003-01-08 19:53 UTC (permalink / raw)
  To: Harald Welte; +Cc: netfilter-devel

Harald Welte writes:
 > Hm. A recursive grep through the kernel doesn't find any occurrance of 
 > 'ipt_matchinfo' at all.
/usr/src/linux-2.4.18/include/linux/netfilter_ipv4/ipt_multiport.h

 > > Ok, then I'll leave it at 10x10x10 (perhaps a lot of overhead for
 > > a single match?)
 > It also means that every single rule containing the u32 match will
 > occupy smp_num_cpus*1000*sizeof(your structure) bytes of non-swappable
 > kernel memory.
Well, not quite that bad.  It's actually o(10x(10+10)).  The structure
sizes seem to be 5+8 so actually using 1300 bytes.  I don't know
whether there's more space wasted on alignment.
Would it work to make that 10 into a module parm (or three) ?

 > >  > I like the content (code/implementation/idea of having u32).
 > >  > The only issue is that it doesn't really fit into the current iptables
 > >  > architecture. Why?
 > >  > 	- because it is a whole classification engine on it's own
 > > Why is this bad?  I wrote it to do things I wanted to do but didn't
 > > see how.  I think that's good.  If it subsumes a few others that are
 > > out there, even better.  (But it's almost certainly a lot slower than 
 > > any more specialized match, so they're still useful.)
 > 
 > Sorry, I didn't make myself clear.  if u32 is used the right way, it is
 > way better than lots of the static matches within iptables.  However, it
I don't know what "the right way" means.  A more specific match will
be faster to execute and easier to specify.  The advantage of u32 is
generality.
 > is more like a replacement of the whole iptables packet matching engine,
 > than a plugin/extension to it.  Making it a plugin/extension will
 > unfortunately become a sort-of clumsy approach.   I don't blame or
 > critisize you... this is not an issue of implementation, but a
 > fundamental architectural problem.

Perhaps you should view it as temporary until something better
arrives.  You might consider changing the architecture later.
My impression is that jamal <hadi@cyberus.ca> is well on the way to
using tc to replace iptables.  And I begin to see that his approach
(or at least what I imagine to be his approach) might actually be
a lot more efficient.  

I notice, btw, that u32 does not do what you'd want for ipv6.
In that case you want to look for a particular header, or of course,
for the end of the headers.  Oh, well.  Another project.

 > yes.  If you now would be as friendly to post it as a unified diff
 > against current patch-o-matic CVS, attached in MIME format?  (And for
 > posting habits and/or coding style hints there are plenty of examples in
 > the list archives respectively CVS).
As you can tell, I'm new at this.  But will give it a try...

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

* Re: iptables u32 match code for review/testing/...
  2003-01-08 19:53           ` Don Cohen
@ 2003-01-08 21:16             ` Harald Welte
  0 siblings, 0 replies; 14+ messages in thread
From: Harald Welte @ 2003-01-08 21:16 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Wed, Jan 08, 2003 at 11:53:49AM -0800, Don Cohen wrote:

> Well, not quite that bad.  It's actually o(10x(10+10)).  The structure
> sizes seem to be 5+8 so actually using 1300 bytes.  I don't know
> whether there's more space wasted on alignment.
> Would it work to make that 10 into a module parm (or three) ?

unfortunately not.  The size of this structure needs to be known at
compile time of the kernel and iptables userspace (and they have to be
the same, obviously).

>  > Sorry, I didn't make myself clear.  if u32 is used the right way, it is
>  > way better than lots of the static matches within iptables.  However, it
> I don't know what "the right way" means.  A more specific match will
> be faster to execute and easier to specify.  The advantage of u32 is
> generality.

You are still comparing u32 to a current iptables match.  What is more
interesting is comaring u32 against a whole iptables chain which uses
only static matches (i.e. matching criteria that can be expressed in u32
syntax).  

> Perhaps you should view it as temporary until something better
> arrives.  You might consider changing the architecture later.
> My impression is that jamal <hadi@cyberus.ca> is well on the way to
> using tc to replace iptables.  And I begin to see that his approach
> (or at least what I imagine to be his approach) might actually be
> a lot more efficient.  

Yes.  Unfortunately I am not able to reproduce the (verbal) discussions
between Jamal, Werner Almesberger, Robert Olsson and me... 
Nobody questions that what he's doing is more efficient.  In fact,
almost anything you can do (with a fundamentally different
architecture) for matching a packet based on static matching criteria
(i.e. port number=x, tos=y, ttl=z, ...) present in the packet header
will be more efficient than iptables.   See also the nf-hipac project.

But will it be as easily extensible as iptables?
Will it support efficient matching of out-of-packet data? (i.e.
state, random, nth, conntrack, helper, ... matches of iptables)

And in the end the question is: How much efficiency at this level do we
need?  In a time of stateful firewalling, most people don't do lots of
classification based on 'static' criteria.  In iptables-terminology: One
of the first rules will be '-m state --state ESTABLISHED -j ACCEPT',
resulting in only a single rule to be iterated for every packet part of
an already established connection... 

-- 
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
"If this were a dictatorship, it'd be a heck of a lot easier, just so long
 as I'm the dictator."  --  George W. Bush Dec 18, 2000

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match patch-o-matic (attempt)
  2003-01-08 10:56         ` Harald Welte
  2003-01-08 19:53           ` Don Cohen
@ 2003-01-08 22:10           ` Don Cohen
  2003-01-11 19:47             ` Harald Welte
  1 sibling, 1 reply; 14+ messages in thread
From: Don Cohen @ 2003-01-08 22:10 UTC (permalink / raw)
  To: Harald Welte; +Cc: netfilter-devel

[-- Attachment #1: message body text --]
[-- Type: text/plain, Size: 773 bytes --]

 > yes.  If you now would be as friendly to post it as a unified diff
 > against current patch-o-matic CVS, attached in MIME format?  (And for
 > posting habits and/or coding style hints there are plenty of examples in
 > the list archives respectively CVS).

I've tried to follow directions in NEWPATCHES.
I don't quite understand, though, where libipt_u32.c belongs.
I guess not in patch-o-matic.
It looks like you want me to download the current patch-o-matic cvs,
make a copy of it with my 3 patch files, then do a diff.
But this just contains my 3 patch files, right?
So wouldn't that be the same as putting those files in one directory,
creating a second directory with empty files of those names and doing
the diff of those?
Anyhow, see if this is what you wanted:


[-- Attachment #2: u32-diff --]
[-- Type: application/octet-stream, Size: 10303 bytes --]

diff -ur u32-empty/u32.patch u32-added/u32.patch
--- u32-empty/u32.patch	Wed Jan  8 14:05:11 2003
+++ u32-added/u32.patch	Wed Jan  8 13:40:47 2003
@@ -0,0 +1,249 @@
+diff -ur /usr/src/linux-2.4.18-clean/include/linux/netfilter_ipv4/ipt_u32.h /usr/src/linux-2.4.18/include/linux/netfilter_ipv4/ipt_u32.h
+--- /usr/src/linux-2.4.18-clean/include/linux/netfilter_ipv4/ipt_u32.h	Wed Jan  8 13:08:47 2003
++++ /usr/src/linux-2.4.18/include/linux/netfilter_ipv4/ipt_u32.h	Tue Jan  7 22:40:38 2003
+@@ -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*/
+diff -ur /usr/src/linux-2.4.18-clean/net/ipv4/netfilter/ipt_u32.c /usr/src/linux-2.4.18/net/ipv4/netfilter/ipt_u32.c
+--- /usr/src/linux-2.4.18-clean/net/ipv4/netfilter/ipt_u32.c	Thu Dec 26 11:04:18 2002
++++ /usr/src/linux-2.4.18/net/ipv4/netfilter/ipt_u32.c	Mon Jan  6 08:49:56 2003
+@@ -0,0 +1,201 @@
++/* 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@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@12>>26&0x3C@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 <asm-i386/timex.h> for timing */
++
++MODULE_AUTHOR("Don Cohen <don@isis.cs3-inc.com>");
++MODULE_DESCRIPTION("IP tables u32 matching module");
++MODULE_LICENSE("GPL");
++
++static int
++match(const struct sk_buff *skb,
++      const struct net_device *in,
++      const struct net_device *out,
++      const void *matchinfo,
++      int offset,
++      const void *hdr,
++      u_int16_t datalen,
++      int *hotdrop)
++{
++	const struct ipt_u32 *data = matchinfo;
++	int testind, i;
++	unsigned char* origbase = (char*)skb->nh.iph;
++	unsigned char* base = origbase;
++	unsigned char* head = skb->head;
++	unsigned char* end = skb->end;
++	int nnums, nvals;
++	u_int32_t pos, val;
++	/* 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) 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); */
++			return 0;
++		}
++	}
++	/* cycles2 = get_cycles();
++	   printk("succeeded in %d cycles\n", cycles2-cycles1); */
++	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
++= { { NULL, NULL }, "u32", &match, &checkentry, NULL, 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);
diff -ur u32-empty/u32.patch.help u32-added/u32.patch.help
--- u32-empty/u32.patch.help	Wed Jan  8 14:05:11 2003
+++ u32-added/u32.patch.help	Wed Jan  8 13:40:47 2003
@@ -0,0 +1,10 @@
+Author: Don Cohen <don@isis.cs3-inc.com>
+Status: Tested locally, seems to work.
+
+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.
diff -ur u32-empty/u32.patch.makefile u32-added/u32.patch.makefile
--- u32-empty/u32.patch.makefile	Wed Jan  8 14:05:11 2003
+++ u32-added/u32.patch.makefile	Wed Jan  8 13:40:47 2003
@@ -0,0 +1,2 @@
+PF_EXT_SLIB+=TTL iplimit
+PF_EXT_SLIB+=u32

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

* Re: iptables u32 match patch-o-matic (attempt)
  2003-01-08 22:10           ` iptables u32 match patch-o-matic (attempt) Don Cohen
@ 2003-01-11 19:47             ` Harald Welte
  2003-01-12 21:11               ` Don Cohen
  0 siblings, 1 reply; 14+ messages in thread
From: Harald Welte @ 2003-01-11 19:47 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Wed, Jan 08, 2003 at 02:10:22PM -0800, Don Cohen wrote:
Content-Description: message body text
>  > yes.  If you now would be as friendly to post it as a unified diff
>  > against current patch-o-matic CVS, attached in MIME format?  (And for
>  > posting habits and/or coding style hints there are plenty of examples in
>  > the list archives respectively CVS).
> 
> I've tried to follow directions in NEWPATCHES.
> I don't quite understand, though, where libipt_u32.c belongs.

no, it just belongs into the extensions subdirectory, together with a
.u32-test shellscript (similar to the others...)

> It looks like you want me to download the current patch-o-matic cvs,
> make a copy of it with my 3 patch files, then do a diff.
> But this just contains my 3 patch files, right?

yup, it is a diff which adds 3 files (of which one is again a diff)

> So wouldn't that be the same as putting those files in one directory,
> creating a second directory with empty files of those names and doing
> the diff of those?

yes, it would turn out the same thing, as long as (like in the usual
case) there are no modifications to existing Makefiles, etc.

> Anyhow, see if this is what you wanted:

couple of comments:

1) please include the patch 'netfilter/userspace' or at least
'userspace', so the patch can be applied from the 'root' netfilter
directory. (this is not really important, but usual) (this is not really
important, but usual)

2) please don't include the u32 in extensions/Makefile.  If you do that,
you would also need to put your kernel header file into
userspace/include/linux/...  - but we only do this for stable matches
which are about to be submitted to the kernel soon.  Instead, we use a
conditional compilation mechanism with the '.foo-test' scripts.

Maybe it's a good idea to have a look at some other patches (like the
recently submitted hoplimit (hl) patches as an example.  I didn't need
to describe this into detail so far, everybody just figured..

.. but it seems like there is a need for documentation.  If you feel
NEWPATCHES should be extended in some way -> patches are welcome ;)

Thanks again.

-- 
Live long and prosper
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
GCS/E/IT d- s-: a-- C+++ UL++++$ P+++ L++++$ E--- W- N++ o? K- w--- O- M- 
V-- PS+ PE-- Y+ PGP++ t++ 5-- !X !R tv-- b+++ DI? !D G+ e* h+ r% y+(*)

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

* Re: iptables u32 match patch-o-matic (attempt)
  2003-01-11 19:47             ` Harald Welte
@ 2003-01-12 21:11               ` Don Cohen
  2003-01-25 18:39                 ` Harald Welte
  0 siblings, 1 reply; 14+ messages in thread
From: Don Cohen @ 2003-01-12 21:11 UTC (permalink / raw)
  To: Harald Welte; +Cc: netfilter-devel

(reshuffling the message to which I reply for better presentation)

It seems a lot easier to write a match than to package it as a patch!
Perhaps my confusion is related to the fact that I went about this
whole process in some unexpected way.  I downloaded iptables-1.2.7a
and patch-o-matic-20020825 in order to look at existing code so I
could write my match.  Then I added stuff that looked similar to what
was there and built it.  I begin to think I should have instead
started with cvs checkout.  I see that contains netfilter/userspace
whereas I have no such directory.

 > Maybe it's a good idea to have a look at some other patches (like the
 > recently submitted hoplimit (hl) patches as an example.  I didn't need
 > to describe this into detail so far, everybody just figured..

I did try to look at other patches.  I think the example you site will
give an idea of the resulting problems:
http://lists.netfilter.org/pipermail/netfilter-devel/2003-January/010135.html
[RESEND][PATCH] Hop Limit match/target for IPv6 
contains about 20 diffs !  (I thought I needed about 3.)
What's the difference between the HL's and the hl's, I wonder.
And the first dozen or so don't contain any userspace.
And then there's a large base64 attachment at the end.

Whereas NEWPATCHES seems to be meant to tell me what to do.

 > > I've tried to follow directions in NEWPATCHES.
 > > I don't quite understand, though, where libipt_u32.c belongs.
 > 
 > no, it just belongs into the extensions subdirectory, together with a
 > .u32-test shellscript (similar to the others...)
This suggests that it should be part of what I send you.
But below you seem to say 3 files, which is what NEWPATCHES seemed
to indicate, and which is what I did send.

 > > It looks like you want me to download the current patch-o-matic cvs,
 > > make a copy of it with my 3 patch files, then do a diff.
 > > But this just contains my 3 patch files, right?
 > yup, it is a diff which adds 3 files (of which one is again a diff)
This is at least consistent with what I sent.

 > > So wouldn't that be the same as putting those files in one directory,
 > > creating a second directory with empty files of those names and doing
 > > the diff of those?
 > 
 > yes, it would turn out the same thing, as long as (like in the usual
 > case) there are no modifications to existing Makefiles, etc.
 > 
 > > Anyhow, see if this is what you wanted:
 > 
 > couple of comments:
 > 
 > 1) please include the patch 'netfilter/userspace' or at least
 > 'userspace', so the patch can be applied from the 'root' netfilter
 > directory. (this is not really important, but usual) (this is not really
 > important, but usual)

Am I correct that the complaint here is that instead of
 diff -ur u32-empty/u32.patch u32-added/u32.patch
you wanted something like
 diff -ur u32-empty/userspace/u32.patch u32-added/userspace/u32.patch
or
 diff -ur u32-empty/netfilter/userspace/u32.patch u32-added/netfilter/userspace/u32.patch
or
 diff -ur netfilter/userspace/u32.patch netfilter/userspace/u32.patch
?

 > 2) please don't include the u32 in extensions/Makefile...
The only Makefile in what I sent was
 diff -ur u32-empty/u32.patch.makefile u32-added/u32.patch.makefile
which was mentioned in NEWPATCHES:
 4) If you want to edit the Makefile...
Maybe you're saying I shouldn't do that.  
In which case
- how should I make u32 ?
- I end up with only 2 files in my patch, so one's missing from the
three that you agree above should be there.  Is that libipt_u32.c ?

 > .. but it seems like there is a need for documentation.  If you feel
 > NEWPATCHES should be extended in some way -> patches are welcome ;)
Sorry to be so dense.  Maybe when I finally see what I should have
done I'll have a better idea of what NEWPATCHES could have said to
lead me to that result.

In the mean while, here's what I regard as a summary of what I sent you.
Please tell me what you want to see in the corresponding summary of
what I send on the next try.
====
 $ grep diff /tmp/u32-diff
 diff -ur u32-empty/u32.patch u32-added/u32.patch
 +diff -ur /usr/src/linux-2.4.18-clean/include/linux/netfilter_ipv4/ipt_u32.h /usr/src/linux-2.4.18/include/linux/netfilter_ipv4/ipt_u32.h
 +diff -ur /usr/src/linux-2.4.18-clean/net/ipv4/netfilter/ipt_u32.c /usr/src/linux-2.4.18/net/ipv4/netfilter/ipt_u32.c
 diff -ur u32-empty/u32.patch.help u32-added/u32.patch.help
 diff -ur u32-empty/u32.patch.makefile u32-added/u32.patch.makefile
====

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

* Re: iptables u32 match patch-o-matic (attempt)
  2003-01-12 21:11               ` Don Cohen
@ 2003-01-25 18:39                 ` Harald Welte
  0 siblings, 0 replies; 14+ messages in thread
From: Harald Welte @ 2003-01-25 18:39 UTC (permalink / raw)
  To: Don Cohen; +Cc: netfilter-devel

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

On Sun, Jan 12, 2003 at 01:11:51PM -0800, Don Cohen wrote:

> It seems a lot easier to write a match than to package it as a patch!

;) I think this is just a matter of getting used to it.  I understand
that patch-o-matic is a little bit complicated at the first look..

> Perhaps my confusion is related to the fact that I went about this
> whole process in some unexpected way.  I downloaded iptables-1.2.7a
> and patch-o-matic-20020825 in order to look at existing code so I
> could write my match.  Then I added stuff that looked similar to what
> was there and built it.  I begin to think I should have instead
> started with cvs checkout.  I see that contains netfilter/userspace
> whereas I have no such directory.

the netfilter/userspace directory is exactly what is packaged as
iptables-*.tar.bz2 archive.

> What's the difference between the HL's and the hl's, I wonder.

HL is hoplimit target, hl is hoplimit match.

> Whereas NEWPATCHES seems to be meant to tell me what to do.

yup. but I think it's a bit out of date and never was completed.

>  > > I've tried to follow directions in NEWPATCHES.
>  > > I don't quite understand, though, where libipt_u32.c belongs.
>  > 
>  > no, it just belongs into the extensions subdirectory, together with a
>  > .u32-test shellscript (similar to the others...)
> This suggests that it should be part of what I send you.
> But below you seem to say 3 files, which is what NEWPATCHES seemed
> to indicate, and which is what I did send.

well. You generate those three files, put them in the patch-o-matic
directory and then do a 'diff -Nru' between a clean patch-o-matic and
your modified version.

the patch thus only contains three hooks, adding three files. one of
them is the previously-mentioned patch file to the kernel tree.

>  > > So wouldn't that be the same as putting those files in one directory,
>  > > creating a second directory with empty files of those names and doing
>  > > the diff of those?
>  > 
>  > yes, it would turn out the same thing, as long as (like in the usual
>  > case) there are no modifications to existing Makefiles, etc.
>  > 
>  > > Anyhow, see if this is what you wanted:
>  > 
>  > couple of comments:
>  > 
>  > 1) please include the patch 'netfilter/userspace' or at least
>  > 'userspace', so the patch can be applied from the 'root' netfilter
>  > directory. (this is not really important, but usual) (this is not really
>  > important, but usual)
> 
> Am I correct that the complaint here is that instead of
>  diff -ur u32-empty/u32.patch u32-added/u32.patch
> you wanted something like
>  diff -ur u32-empty/userspace/u32.patch u32-added/userspace/u32.patch
> or
>  diff -ur u32-empty/netfilter/userspace/u32.patch u32-added/netfilter/userspace/u32.patch
> or
>  diff -ur netfilter/userspace/u32.patch netfilter/userspace/u32.patch
> ?

no. I'm really surprised that it seems to be that difficult to explain
in which format the patches are submitted in the ideal case.

And I have the feeling that I would spend more time explaining it in an
email than it actually takes to package the patch in the correct format.

So please just send me anything you have and I will bring it into the
correct format as soon as I have some time left.

> - how should I make u32 ?

add the userspace/extensions/.test-u32 script, similar to 

-- 
Live long and prosper
- Harald Welte / laforge@gnumonks.org               http://www.gnumonks.org/
============================================================================
GCS/E/IT d- s-: a-- C+++ UL++++$ P+++ L++++$ E--- W- N++ o? K- w--- O- M- 
V-- PS+ PE-- Y+ PGP++ t++ 5-- !X !R tv-- b+++ DI? !D G+ e* h+ r% y+(*)

[-- Attachment #2: Type: application/pgp-signature, Size: 232 bytes --]

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

end of thread, other threads:[~2003-01-25 18:39 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-12-27 18:54 iptables u32 match code for review/testing/ Don Cohen
2003-01-06 12:57 ` Harald Welte
2003-01-06 17:04   ` Don Cohen
2003-01-07 18:57     ` Harald Welte
2003-01-08  6:41       ` Don Cohen
2003-01-08 10:31         ` Roberto Nibali
2003-01-08 10:56         ` Harald Welte
2003-01-08 19:53           ` Don Cohen
2003-01-08 21:16             ` Harald Welte
2003-01-08 22:10           ` iptables u32 match patch-o-matic (attempt) Don Cohen
2003-01-11 19:47             ` Harald Welte
2003-01-12 21:11               ` Don Cohen
2003-01-25 18:39                 ` Harald Welte
2003-01-07 18:53 ` iptables u32 match code for review/testing/ Harald Welte

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.