Hi, There are two new match: HBH options: --hbh-len [!] length total length of this header --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] Options and its length (list, max: 16)
DST options: --dst-len [!] length total length of this header --dst-opts TYPE[:LEN][,TYPE[:LEN]...] Options and its length (list, max: 16) (Only the first DST options header.) The code of these two match (mainly) the same, but in this form we can load it twice. Now, the supported IPv6 headers: - IPv6 - IPv6 ext headers (general) - Hop-by-Hop - Routing + Type0 Routing - Fragmentation - Destination options - AH - ESP So, we can check all the fileds (or most of them). Regards, kisza -- Andras Kis-Szabo Security Development, Design and Audit -------------------------/ Zorp, NetFilter and IPv6 [EMAIL PROTECTED] /-----Member of the BUTE-MIS-SEARCHlab------>
diff -urN netfilter/userspace/extensions/.opts-test6 netfilter.new/userspace/extensions/.opts-test6 --- netfilter/userspace/extensions/.opts-test6 Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/extensions/.opts-test6 Sat Apr 27 20:49:23 2002 @@ -0,0 +1,2 @@ +#!/bin/sh +[ -f $KERNEL_DIR/net/ipv6/netfilter/ip6t_hbh.c -a -f $KERNEL_DIR/net/ipv6/netfilter/ip6t_dst.c -a -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_opts.h ] && echo hbh dst diff -urN netfilter/userspace/extensions/libip6t_dst.c netfilter.new/userspace/extensions/libip6t_dst.c --- netfilter/userspace/extensions/libip6t_dst.c Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/extensions/libip6t_dst.c Sat Apr 27 23:00:14 2002 @@ -0,0 +1,285 @@ +/* Shared library add-on to ip6tables to add Hop-by-Hop and Dst headers support. */ +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <errno.h> +#include <ip6tables.h> +/*#include <linux/in6.h>*/ +#include <linux/netfilter_ipv6/ip6t_opts.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#define DEBUG 0 +#define HOPBYHOP 0 +#define UNAME (HOPBYHOP ? "HBH" : "DST") +#define LNAME (HOPBYHOP ? "hbh" : "dst") + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"%s v%s options:\n" +" --%s-len [!] length total length of this header\n" +" --%s-opts TYPE[:LEN][,TYPE[:LEN]...] \n" +" Options and its length (list, max: %d)\n", +UNAME , NETFILTER_VERSION, LNAME, LNAME, IP6T_OPTS_OPTSNR); +} + +#if HOPBYHOP +static struct option opts[] = { + { "hbh-len", 1, 0, '1' }, + { "hbh-opts", 1, 0, '2' }, + { "hbh-not-strict", 1, 0, '3' }, + {0} +}; +#else +static struct option opts[] = { + { "dst-len", 1, 0, '1' }, + { "dst-opts", 1, 0, '2' }, + { "dst-not-strict", 1, 0, '3' }, + {0} +}; +#endif + +static u_int32_t +parse_opts_num(const char *idstr, const char *typestr) +{ + unsigned long int id; + char* ep; + + id = strtoul(idstr,&ep,0) ; + + if ( idstr == ep ) { + exit_error(PARAMETER_PROBLEM, + "%s no valid digits in %s `%s'", UNAME, typestr, idstr); + } + if ( id == ULONG_MAX && errno == ERANGE ) { + exit_error(PARAMETER_PROBLEM, + "%s `%s' specified too big: would overflow", + typestr, idstr); + } + if ( *idstr != '\0' && *ep != '\0' ) { + exit_error(PARAMETER_PROBLEM, + "%s error parsing %s `%s'", UNAME, typestr, idstr); + } + return (u_int32_t) id; +} + +static int +parse_options(const char *optsstr, u_int16_t *opts) +{ + char *buffer, *cp, *next, *range; + unsigned int i; + + buffer = strdup(optsstr); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++) + { + next=strchr(cp, ','); + if (next) *next++='\0'; + range = strchr(cp, ':'); + if (range) { + if (i == IP6T_OPTS_OPTSNR-1) + exit_error(PARAMETER_PROBLEM, + "too many ports specified"); + *range++ = '\0'; + } + opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8); + if (range) { + if (opts[i] == 0) + exit_error(PARAMETER_PROBLEM, "PAD0 hasn't got length"); + opts[i] |= (u_int16_t)(parse_opts_num(range,"length") & + 0x000000FF); + } else { + opts[i] |= (0x00FF); + } + +#if DEBUG + printf("opts str: %s %s\n", cp, range); + printf("opts opt: %04X\n", opts[i]); +#endif + } + if (cp) exit_error(PARAMETER_PROBLEM, "too many addresses specified"); + + free(buffer); + +#if DEBUG + printf("addr nr: %d\n", i); +#endif + + return i; +} + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; + + optinfo->hdrlen = 0; + optinfo->flags = 0; + optinfo->invflags = 0; + optinfo->optsnr = 0; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; + + switch (c) { + case '1': + if (*flags & IP6T_OPTS_LEN) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-len' allowed", LNAME); + check_inverse(optarg, &invert, &optind, 0); + optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); + if (invert) + optinfo->invflags |= IP6T_OPTS_INV_LEN; + optinfo->flags |= IP6T_OPTS_LEN; + *flags |= IP6T_OPTS_LEN; + break; + case '2': + if (*flags & IP6T_OPTS_OPTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-opts' allowed", LNAME); + check_inverse(optarg, &invert, &optind, 0); + if (invert) + exit_error(PARAMETER_PROBLEM, + " '!' not allowed with `--%s-opts'", LNAME); + optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); + optinfo->flags |= IP6T_OPTS_OPTS; + *flags |= IP6T_OPTS_OPTS; + break; + case '3': + if (*flags & IP6T_OPTS_NSTRICT) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-not-strict' allowed", LNAME); + if ( !(*flags & IP6T_OPTS_OPTS) ) + exit_error(PARAMETER_PROBLEM, + "`--%s-opts ...' required before `--%s-not-strict'", LNAME, LNAME); + optinfo->flags |= IP6T_OPTS_NSTRICT; + *flags |= IP6T_OPTS_NSTRICT; + break; + default: + return 0; + } + + return 1; +} + +/* Final check; we don't care. */ +static void +final_check(unsigned int flags) +{ +} + +static void +print_nums(const char *name, u_int32_t min, u_int32_t max, + int invert) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFFFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + printf("%u", min); + } else { + printf("s:%s", inv); + printf("%u",min); + printf(":"); + printf("%u",max); + } + printf(" "); + } +} + +static void +print_options(int optsnr, u_int16_t *optsp) +{ + unsigned int i; + + for(i=0; i<optsnr; i++){ + printf("%d", (optsp[i] & 0xFF00)>>8); + if ((optsp[i] & 0x00FF) != 0x00FF){ + printf(":%d", (optsp[i] & 0x00FF)); + } + printf("%c", (i!=optsnr-1)?',':' '); + } +} + +/* Prints out the union ip6t_matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, int numeric) +{ + const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; + + printf("%s ", LNAME); + if (optinfo->flags & IP6T_OPTS_LEN) { + printf("length"); + printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); + printf("%u", optinfo->hdrlen); + printf(" "); + } + if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); + print_options(optinfo->optsnr, optinfo->opts); + if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); + if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) + printf("Unknown invflags: 0x%X ", + optinfo->invflags & ~IP6T_OPTS_INV_MASK); +} + +/* Saves the union ip6t_matchinfo in parsable form to stdout. */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; + + if (optinfo->flags & IP6T_OPTS_LEN) { + printf("--%s-len %s%u ", LNAME, + (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", + optinfo->hdrlen); + } + + if (optinfo->flags & IP6T_OPTS_OPTS) printf("--%s-opts ", LNAME); + print_options(optinfo->optsnr, optinfo->opts); + if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("--%s-not-strict ", LNAME); + +} + +static +struct ip6tables_match optstruct += { NULL, +#if HOPBYHOP + "hbh", +#else + "dst", +#endif + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_opts)), + IP6T_ALIGN(sizeof(struct ip6t_opts)), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void +_init(void) +{ + register_match6(&optstruct); +} diff -urN netfilter/userspace/extensions/libip6t_hbh.c netfilter.new/userspace/extensions/libip6t_hbh.c --- netfilter/userspace/extensions/libip6t_hbh.c Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/extensions/libip6t_hbh.c Sat Apr 27 23:00:05 2002 @@ -0,0 +1,285 @@ +/* Shared library add-on to ip6tables to add Hop-by-Hop and Dst headers support. */ +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <errno.h> +#include <ip6tables.h> +/*#include <linux/in6.h>*/ +#include <linux/netfilter_ipv6/ip6t_opts.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> + +#define DEBUG 0 +#define HOPBYHOP 1 +#define UNAME (HOPBYHOP ? "HBH" : "DST") +#define LNAME (HOPBYHOP ? "hbh" : "dst") + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"%s v%s options:\n" +" --%s-len [!] length total length of this header\n" +" --%s-opts TYPE[:LEN][,TYPE[:LEN]...] \n" +" Options and its length (list, max: %d)\n", +UNAME , NETFILTER_VERSION, LNAME, LNAME, IP6T_OPTS_OPTSNR); +} + +#if HOPBYHOP +static struct option opts[] = { + { "hbh-len", 1, 0, '1' }, + { "hbh-opts", 1, 0, '2' }, + { "hbh-not-strict", 1, 0, '3' }, + {0} +}; +#else +static struct option opts[] = { + { "dst-len", 1, 0, '1' }, + { "dst-opts", 1, 0, '2' }, + { "dst-not-strict", 1, 0, '3' }, + {0} +}; +#endif + +static u_int32_t +parse_opts_num(const char *idstr, const char *typestr) +{ + unsigned long int id; + char* ep; + + id = strtoul(idstr,&ep,0) ; + + if ( idstr == ep ) { + exit_error(PARAMETER_PROBLEM, + "%s no valid digits in %s `%s'", UNAME, typestr, idstr); + } + if ( id == ULONG_MAX && errno == ERANGE ) { + exit_error(PARAMETER_PROBLEM, + "%s `%s' specified too big: would overflow", + typestr, idstr); + } + if ( *idstr != '\0' && *ep != '\0' ) { + exit_error(PARAMETER_PROBLEM, + "%s error parsing %s `%s'", UNAME, typestr, idstr); + } + return (u_int32_t) id; +} + +static int +parse_options(const char *optsstr, u_int16_t *opts) +{ + char *buffer, *cp, *next, *range; + unsigned int i; + + buffer = strdup(optsstr); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++) + { + next=strchr(cp, ','); + if (next) *next++='\0'; + range = strchr(cp, ':'); + if (range) { + if (i == IP6T_OPTS_OPTSNR-1) + exit_error(PARAMETER_PROBLEM, + "too many ports specified"); + *range++ = '\0'; + } + opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8); + if (range) { + if (opts[i] == 0) + exit_error(PARAMETER_PROBLEM, "PAD0 hasn't got length"); + opts[i] |= (u_int16_t)(parse_opts_num(range,"length") & + 0x000000FF); + } else { + opts[i] |= (0x00FF); + } + +#if DEBUG + printf("opts str: %s %s\n", cp, range); + printf("opts opt: %04X\n", opts[i]); +#endif + } + if (cp) exit_error(PARAMETER_PROBLEM, "too many addresses specified"); + + free(buffer); + +#if DEBUG + printf("addr nr: %d\n", i); +#endif + + return i; +} + +/* Initialize the match. */ +static void +init(struct ip6t_entry_match *m, unsigned int *nfcache) +{ + struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; + + optinfo->hdrlen = 0; + optinfo->flags = 0; + optinfo->invflags = 0; + optinfo->optsnr = 0; +} + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ip6t_entry *entry, + unsigned int *nfcache, + struct ip6t_entry_match **match) +{ + struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; + + switch (c) { + case '1': + if (*flags & IP6T_OPTS_LEN) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-len' allowed", LNAME); + check_inverse(optarg, &invert, &optind, 0); + optinfo->hdrlen = parse_opts_num(argv[optind-1], "length"); + if (invert) + optinfo->invflags |= IP6T_OPTS_INV_LEN; + optinfo->flags |= IP6T_OPTS_LEN; + *flags |= IP6T_OPTS_LEN; + break; + case '2': + if (*flags & IP6T_OPTS_OPTS) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-opts' allowed", LNAME); + check_inverse(optarg, &invert, &optind, 0); + if (invert) + exit_error(PARAMETER_PROBLEM, + " '!' not allowed with `--%s-opts'", LNAME); + optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts); + optinfo->flags |= IP6T_OPTS_OPTS; + *flags |= IP6T_OPTS_OPTS; + break; + case '3': + if (*flags & IP6T_OPTS_NSTRICT) + exit_error(PARAMETER_PROBLEM, + "Only one `--%s-not-strict' allowed", LNAME); + if ( !(*flags & IP6T_OPTS_OPTS) ) + exit_error(PARAMETER_PROBLEM, + "`--%s-opts ...' required before `--%s-not-strict'", LNAME, LNAME); + optinfo->flags |= IP6T_OPTS_NSTRICT; + *flags |= IP6T_OPTS_NSTRICT; + break; + default: + return 0; + } + + return 1; +} + +/* Final check; we don't care. */ +static void +final_check(unsigned int flags) +{ +} + +static void +print_nums(const char *name, u_int32_t min, u_int32_t max, + int invert) +{ + const char *inv = invert ? "!" : ""; + + if (min != 0 || max != 0xFFFFFFFF || invert) { + printf("%s", name); + if (min == max) { + printf(":%s", inv); + printf("%u", min); + } else { + printf("s:%s", inv); + printf("%u",min); + printf(":"); + printf("%u",max); + } + printf(" "); + } +} + +static void +print_options(int optsnr, u_int16_t *optsp) +{ + unsigned int i; + + for(i=0; i<optsnr; i++){ + printf("%d", (optsp[i] & 0xFF00)>>8); + if ((optsp[i] & 0x00FF) != 0x00FF){ + printf(":%d", (optsp[i] & 0x00FF)); + } + printf("%c", (i!=optsnr-1)?',':' '); + } +} + +/* Prints out the union ip6t_matchinfo. */ +static void +print(const struct ip6t_ip6 *ip, + const struct ip6t_entry_match *match, int numeric) +{ + const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; + + printf("%s ", LNAME); + if (optinfo->flags & IP6T_OPTS_LEN) { + printf("length"); + printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); + printf("%u", optinfo->hdrlen); + printf(" "); + } + if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); + print_options(optinfo->optsnr, optinfo->opts); + if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); + if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) + printf("Unknown invflags: 0x%X ", + optinfo->invflags & ~IP6T_OPTS_INV_MASK); +} + +/* Saves the union ip6t_matchinfo in parsable form to stdout. */ +static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match) +{ + const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; + + if (optinfo->flags & IP6T_OPTS_LEN) { + printf("--%s-len %s%u ", LNAME, + (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", + optinfo->hdrlen); + } + + if (optinfo->flags & IP6T_OPTS_OPTS) printf("--%s-opts ", LNAME); + print_options(optinfo->optsnr, optinfo->opts); + if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("--%s-not-strict ", LNAME); + +} + +static +struct ip6tables_match optstruct += { NULL, +#if HOPBYHOP + "hbh", +#else + "dst", +#endif + NETFILTER_VERSION, + IP6T_ALIGN(sizeof(struct ip6t_opts)), + IP6T_ALIGN(sizeof(struct ip6t_opts)), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void +_init(void) +{ + register_match6(&optstruct); +} diff -urN netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6 netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6 --- netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6 Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6 Sat Apr 27 23:43:02 2002 @@ -0,0 +1,618 @@ +diff -urN linux-2.4.18.hoi.1.1/include/linux/netfilter_ipv6/ip6t_opts.h linux/include/linux/netfilter_ipv6/ip6t_opts.h +--- linux-2.4.18.hoi.1.1/include/linux/netfilter_ipv6/ip6t_opts.h Thu Jan 1 01:00:00 1970 ++++ linux/include/linux/netfilter_ipv6/ip6t_opts.h Mon Apr 22 01:04:24 2002 +@@ -0,0 +1,32 @@ ++#ifndef _IP6T_OPTS_H ++#define _IP6T_OPTS_H ++ ++#define IP6T_OPTS_OPTSNR 16 ++ ++struct ip6t_opts ++{ ++ u_int32_t hdrlen; /* Header Length */ ++ u_int8_t flags; /* */ ++ u_int8_t invflags; /* Inverse flags */ ++ u_int16_t opts[IP6T_OPTS_OPTSNR]; /* opts */ ++ u_int8_t optsnr; /* Nr of OPts */ ++}; ++ ++#define IP6T_OPTS_LEN 0x01 ++#define IP6T_OPTS_OPTS 0x02 ++#define IP6T_OPTS_NSTRICT 0x04 ++ ++/* Values for "invflags" field in struct ip6t_rt. */ ++#define IP6T_OPTS_INV_LEN 0x01 /* Invert the sense of length. */ ++#define IP6T_OPTS_INV_MASK 0x01 /* All possible flags. */ ++ ++#define MASK_HOPOPTS 128 ++#define MASK_DSTOPTS 64 ++#define MASK_ROUTING 32 ++#define MASK_FRAGMENT 16 ++#define MASK_AH 8 ++#define MASK_ESP 4 ++#define MASK_NONE 2 ++#define MASK_PROTO 1 ++ ++#endif /*_IP6T_OPTS_H*/ +diff -urN linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_hbh.c linux/net/ipv6/netfilter/ip6t_hbh.c +--- linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_hbh.c Thu Jan 1 01:00:00 1970 ++++ linux/net/ipv6/netfilter/ip6t_hbh.c Mon Apr 22 02:55:04 2002 +@@ -0,0 +1,287 @@ ++/* Kernel module to match Hop-by-Hop and Destination parameters. */ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/ipv6.h> ++#include <linux/types.h> ++#include <net/checksum.h> ++#include <net/ipv6.h> ++ ++#include <asm/byteorder.h> ++ ++#include <linux/netfilter_ipv6/ip6_tables.h> ++#include <linux/netfilter_ipv6/ip6t_opts.h> ++ ++#define LOW(n) (n & 0x00FF) ++ ++#define HOPBYHOP 1 ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++#if HOPBYHOP ++MODULE_DESCRIPTION("IPv6 HbH match"); ++#else ++MODULE_DESCRIPTION("IPv6 DST match"); ++#endif ++MODULE_AUTHOR("Andras Kis-Szabo <[EMAIL PROTECTED]>"); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++int ipv6_ext_hdr(u8 nexthdr) ++{ ++ return ( (nexthdr == NEXTHDR_HOP) || ++ (nexthdr == NEXTHDR_ROUTING) || ++ (nexthdr == NEXTHDR_FRAGMENT) || ++ (nexthdr == NEXTHDR_AUTH) || ++ (nexthdr == NEXTHDR_ESP) || ++ (nexthdr == NEXTHDR_NONE) || ++ (nexthdr == NEXTHDR_DEST) ); ++} ++ ++/* ++ * (Type & 0xC0) >> 6 ++ * 0 -> ignorable ++ * 1 -> must drop the packet ++ * 2 -> send ICMP PARM PROB regardless and drop packet ++ * 3 -> Send ICMP if not a multicast address and drop packet ++ * (Type & 0x20) >> 5 ++ * 0 -> invariant ++ * 1 -> can change the routing ++ * (Type & 0x1F) Type ++ * 0 -> PAD0 (only 1 byte!) ++ * 1 -> PAD1 LENGTH info (total length = length + 2) ++ * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) ++ * 5 -> RTALERT 2 x x ++ */ ++ ++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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ipv6_opt_hdr *optsh = NULL; ++ const struct ip6t_opts *optinfo = matchinfo; ++ unsigned int temp; ++ unsigned int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ unsigned int ret = 0; ++ u_int16_t *optdesc = NULL; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ipv6_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_opts header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(void *)(skb->data)+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* OPTS -> evaluate */ ++#if HOPBYHOP ++ if (nexthdr == NEXTHDR_HOP) { ++ temp |= MASK_HOPOPTS; ++#else ++ if (nexthdr == NEXTHDR_DEST) { ++ temp |= MASK_DSTOPTS; ++#endif ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_opts: new pointer is too large! \n"); ++ break; ++ } ++ } ++ ++ /* OPTIONS header not found */ ++#if HOPBYHOP ++ if ( temp != MASK_HOPOPTS ) return 0; ++#else ++ if ( temp != MASK_DSTOPTS ) return 0; ++#endif ++ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ if (len < hdrlen){ ++ /* Packet smaller than it's length field */ ++ return 0; ++ } ++ ++ optsh=(void *)(skb->data)+ptr; ++ ++ DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); ++ ++ DEBUGP("len %02X %04X %02X ", ++ optinfo->hdrlen, hdrlen, ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); ++ ++ ret = (optsh != NULL) ++ && ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); ++ ++ temp = len = 0; ++ ptr += 2; ++ hdrlen -= 2; ++ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ ++ return ret; ++ } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { ++ DEBUGP("Not strict - not implemented"); ++ } else { ++ DEBUGP("Strict "); ++ DEBUGP("#%d ",optinfo->optsnr); ++ for(temp=0; temp<optinfo->optsnr; temp++){ ++ optdesc = (void *)(skb->data)+ptr; ++ /* Type check */ ++ if ( (unsigned char)*optdesc != ++ (optinfo->opts[temp] & 0xFF00)>>8 ){ ++ DEBUGP("Tbad %02X %02X\n", ++ (unsigned char)*optdesc, ++ (optinfo->opts[temp] & ++ 0xFF00)>>8); ++ return 0; ++ } else { ++ DEBUGP("Tok "); ++ } ++ /* Length check */ ++ if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && ++ (unsigned char)*optdesc != 0){ ++ if ( ntohs((u16)*optdesc) != ++ optinfo->opts[temp] ){ ++ DEBUGP("Lbad %02X %04X %04X\n", ++ (unsigned char)*optdesc, ++ ntohs((u16)*optdesc), ++ optinfo->opts[temp]); ++ return 0; ++ } else { ++ DEBUGP("Lok "); ++ } ++ } ++ /* Step to the next */ ++ if ((unsigned char)*optdesc == 0){ ++ DEBUGP("PAD0 \n"); ++ ptr++; ++ hdrlen--; ++ } else { ++ ptr += LOW(ntohs(*optdesc)); ++ hdrlen -= LOW(ntohs(*optdesc)); ++ DEBUGP("len%04X \n", ++ LOW(ntohs(*optdesc))); ++ } ++ if (ptr > skb->len || ( !hdrlen && ++ (temp != optinfo->optsnr - 1))) { ++ DEBUGP("new pointer is too large! \n"); ++ break; ++ } ++ } ++ if (temp == optinfo->optsnr) ++ return ret; ++ else return 0; ++ } ++ ++ return 0; ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_opts *optsinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { ++ DEBUGP("ip6t_opts: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); ++ return 0; ++ } ++ if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { ++ DEBUGP("ip6t_opts: unknown flags %X\n", ++ optsinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match opts_match ++#if HOPBYHOP ++= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE }; ++#else ++= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE }; ++#endif ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&opts_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&opts_match); ++} ++ ++module_init(init); ++module_exit(cleanup); +diff -urN linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_dst.c linux/net/ipv6/netfilter/ip6t_dst.c +--- linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_dst.c Thu Jan 1 01:00:00 1970 ++++ linux/net/ipv6/netfilter/ip6t_dst.c Mon Apr 22 02:55:04 2002 +@@ -0,0 +1,287 @@ ++/* Kernel module to match Hop-by-Hop and Destination parameters. */ ++#include <linux/module.h> ++#include <linux/skbuff.h> ++#include <linux/ipv6.h> ++#include <linux/types.h> ++#include <net/checksum.h> ++#include <net/ipv6.h> ++ ++#include <asm/byteorder.h> ++ ++#include <linux/netfilter_ipv6/ip6_tables.h> ++#include <linux/netfilter_ipv6/ip6t_opts.h> ++ ++#define LOW(n) (n & 0x00FF) ++ ++#define HOPBYHOP 0 ++ ++EXPORT_NO_SYMBOLS; ++MODULE_LICENSE("GPL"); ++#if HOPBYHOP ++MODULE_DESCRIPTION("IPv6 HbH match"); ++#else ++MODULE_DESCRIPTION("IPv6 DST match"); ++#endif ++MODULE_AUTHOR("Andras Kis-Szabo <[EMAIL PROTECTED]>"); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++int ipv6_ext_hdr(u8 nexthdr) ++{ ++ return ( (nexthdr == NEXTHDR_HOP) || ++ (nexthdr == NEXTHDR_ROUTING) || ++ (nexthdr == NEXTHDR_FRAGMENT) || ++ (nexthdr == NEXTHDR_AUTH) || ++ (nexthdr == NEXTHDR_ESP) || ++ (nexthdr == NEXTHDR_NONE) || ++ (nexthdr == NEXTHDR_DEST) ); ++} ++ ++/* ++ * (Type & 0xC0) >> 6 ++ * 0 -> ignorable ++ * 1 -> must drop the packet ++ * 2 -> send ICMP PARM PROB regardless and drop packet ++ * 3 -> Send ICMP if not a multicast address and drop packet ++ * (Type & 0x20) >> 5 ++ * 0 -> invariant ++ * 1 -> can change the routing ++ * (Type & 0x1F) Type ++ * 0 -> PAD0 (only 1 byte!) ++ * 1 -> PAD1 LENGTH info (total length = length + 2) ++ * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) ++ * 5 -> RTALERT 2 x x ++ */ ++ ++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 *protohdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ struct ipv6_opt_hdr *optsh = NULL; ++ const struct ip6t_opts *optinfo = matchinfo; ++ unsigned int temp; ++ unsigned int len; ++ u8 nexthdr; ++ unsigned int ptr; ++ unsigned int hdrlen = 0; ++ unsigned int ret = 0; ++ u_int16_t *optdesc = NULL; ++ ++ /* type of the 1st exthdr */ ++ nexthdr = skb->nh.ipv6h->nexthdr; ++ /* pointer to the 1st exthdr */ ++ ptr = sizeof(struct ipv6hdr); ++ /* available length */ ++ len = skb->len - ptr; ++ temp = 0; ++ ++ while (ipv6_ext_hdr(nexthdr)) { ++ struct ipv6_opt_hdr *hdr; ++ ++ DEBUGP("ipv6_opts header iteration \n"); ++ ++ /* Is there enough space for the next ext header? */ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)) ++ return 0; ++ /* No more exthdr -> evaluate */ ++ if (nexthdr == NEXTHDR_NONE) { ++ break; ++ } ++ /* ESP -> evaluate */ ++ if (nexthdr == NEXTHDR_ESP) { ++ break; ++ } ++ ++ hdr=(void *)(skb->data)+ptr; ++ ++ /* Calculate the header length */ ++ if (nexthdr == NEXTHDR_FRAGMENT) { ++ hdrlen = 8; ++ } else if (nexthdr == NEXTHDR_AUTH) ++ hdrlen = (hdr->hdrlen+2)<<2; ++ else ++ hdrlen = ipv6_optlen(hdr); ++ ++ /* OPTS -> evaluate */ ++#if HOPBYHOP ++ if (nexthdr == NEXTHDR_HOP) { ++ temp |= MASK_HOPOPTS; ++#else ++ if (nexthdr == NEXTHDR_DEST) { ++ temp |= MASK_DSTOPTS; ++#endif ++ break; ++ } ++ ++ ++ /* set the flag */ ++ switch (nexthdr){ ++ case NEXTHDR_HOP: ++ case NEXTHDR_ROUTING: ++ case NEXTHDR_FRAGMENT: ++ case NEXTHDR_AUTH: ++ case NEXTHDR_DEST: ++ break; ++ default: ++ DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); ++ return 0; ++ break; ++ } ++ ++ nexthdr = hdr->nexthdr; ++ len -= hdrlen; ++ ptr += hdrlen; ++ if ( ptr > skb->len ) { ++ DEBUGP("ipv6_opts: new pointer is too large! \n"); ++ break; ++ } ++ } ++ ++ /* OPTIONS header not found */ ++#if HOPBYHOP ++ if ( temp != MASK_HOPOPTS ) return 0; ++#else ++ if ( temp != MASK_DSTOPTS ) return 0; ++#endif ++ ++ if (len < (int)sizeof(struct ipv6_opt_hdr)){ ++ *hotdrop = 1; ++ return 0; ++ } ++ ++ if (len < hdrlen){ ++ /* Packet smaller than it's length field */ ++ return 0; ++ } ++ ++ optsh=(void *)(skb->data)+ptr; ++ ++ DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); ++ ++ DEBUGP("len %02X %04X %02X ", ++ optinfo->hdrlen, hdrlen, ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); ++ ++ ret = (optsh != NULL) ++ && ++ (!(optinfo->flags & IP6T_OPTS_LEN) || ++ ((optinfo->hdrlen == hdrlen) ^ ++ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))); ++ ++ temp = len = 0; ++ ptr += 2; ++ hdrlen -= 2; ++ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ ++ return ret; ++ } else if (optinfo->flags & IP6T_OPTS_NSTRICT) { ++ DEBUGP("Not strict - not implemented"); ++ } else { ++ DEBUGP("Strict "); ++ DEBUGP("#%d ",optinfo->optsnr); ++ for(temp=0; temp<optinfo->optsnr; temp++){ ++ optdesc = (void *)(skb->data)+ptr; ++ /* Type check */ ++ if ( (unsigned char)*optdesc != ++ (optinfo->opts[temp] & 0xFF00)>>8 ){ ++ DEBUGP("Tbad %02X %02X\n", ++ (unsigned char)*optdesc, ++ (optinfo->opts[temp] & ++ 0xFF00)>>8); ++ return 0; ++ } else { ++ DEBUGP("Tok "); ++ } ++ /* Length check */ ++ if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && ++ (unsigned char)*optdesc != 0){ ++ if ( ntohs((u16)*optdesc) != ++ optinfo->opts[temp] ){ ++ DEBUGP("Lbad %02X %04X %04X\n", ++ (unsigned char)*optdesc, ++ ntohs((u16)*optdesc), ++ optinfo->opts[temp]); ++ return 0; ++ } else { ++ DEBUGP("Lok "); ++ } ++ } ++ /* Step to the next */ ++ if ((unsigned char)*optdesc == 0){ ++ DEBUGP("PAD0 \n"); ++ ptr++; ++ hdrlen--; ++ } else { ++ ptr += LOW(ntohs(*optdesc)); ++ hdrlen -= LOW(ntohs(*optdesc)); ++ DEBUGP("len%04X \n", ++ LOW(ntohs(*optdesc))); ++ } ++ if (ptr > skb->len || ( !hdrlen && ++ (temp != optinfo->optsnr - 1))) { ++ DEBUGP("new pointer is too large! \n"); ++ break; ++ } ++ } ++ if (temp == optinfo->optsnr) ++ return ret; ++ else return 0; ++ } ++ ++ return 0; ++} ++ ++/* Called when user tries to insert an entry of this type. */ ++static int ++checkentry(const char *tablename, ++ const struct ip6t_ip6 *ip, ++ void *matchinfo, ++ unsigned int matchinfosize, ++ unsigned int hook_mask) ++{ ++ const struct ip6t_opts *optsinfo = matchinfo; ++ ++ if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_opts))) { ++ DEBUGP("ip6t_opts: matchsize %u != %u\n", ++ matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_opts))); ++ return 0; ++ } ++ if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) { ++ DEBUGP("ip6t_opts: unknown flags %X\n", ++ optsinfo->invflags); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ip6t_match opts_match ++#if HOPBYHOP ++= { { NULL, NULL }, "hbh", &match, &checkentry, NULL, THIS_MODULE }; ++#else ++= { { NULL, NULL }, "dst", &match, &checkentry, NULL, THIS_MODULE }; ++#endif ++ ++static int __init init(void) ++{ ++ return ip6t_register_match(&opts_match); ++} ++ ++static void __exit cleanup(void) ++{ ++ ip6t_unregister_match(&opts_match); ++} ++ ++module_init(init); ++module_exit(cleanup); diff -urN netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.config.in netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.config.in --- netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.config.in Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.config.in Sat Apr 27 23:35:26 2002 @@ -0,0 +1,4 @@ + dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Hop-by-Hop and Dst opts header match (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_OPTS $CONFIG_IP6_NF_IPTABLES + fi diff -urN netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.configure.help netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.configure.help --- netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.configure.help Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.configure.help Sat Apr 27 23:36:32 2002 @@ -0,0 +1,9 @@ +CONFIG_IP6_NF_MATCH_MAC +Fragmentation header match support (EXPERIMENTAL) +CONFIG_IP6_NF_MATCH_OPTS + These match extensions (`hbh' and `dst') allow you to select the packet + based on the fileds of the option header of the IPv6 packets. + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + diff -urN netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.help netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.help --- netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.help Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.help Sat Apr 27 23:39:18 2002 @@ -0,0 +1,16 @@ +Author: Andras Kis-Szabo <[EMAIL PROTECTED]> +Status: It works 4 me! + + These match extensions (`hbh' and `dst') allow you to select the packet + based on the fileds of the option header of the IPv6 packets. + +HBH options: + --hbh-len [!] length total length of this header + --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] + Options and its length (list, max: 16) + +DST options: + --dst-len [!] length total length of this header + --dst-opts TYPE[:LEN][,TYPE[:LEN]...] + Options and its length (list, max: 16) + diff -urN netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.makefile netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.makefile --- netfilter/userspace/patch-o-matic/base/opts6.patch.ipv6.makefile Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/patch-o-matic/base/opts6.patch.ipv6.makefile Sat Apr 27 23:39:52 2002 @@ -0,0 +1,2 @@ +obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o +obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o