Hi, ChangeLog route6 - Type0 address handling (up to 16 addresses) - 'soft' mode (--rt-0-not-strict): the address list in the packet is not exactly the same, but contains all the specified addresses in the same order
extensions-HOWTO: - frag6 (fragmentation header) match - route6 (routing header) match 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/.rt-test6 netfilter.new/userspace/extensions/.rt-test6 --- netfilter/userspace/extensions/.rt-test6 Thu Jan 1 01:00:00 1970 +++ netfilter.new/userspace/extensions/.rt-test6 Fri Apr 26 23:17:22 2002 @@ -0,0 +1,2 @@ +#!/bin/sh +[ -f $KERNEL_DIR/net/ipv6/netfilter/ip6t_rt.c -a -f $KERNEL_DIR/include/linux/netfilter_ipv6/ip6t_rt.h ] && echo rt diff -urN netfilter/userspace/extensions/libip6t_rt.c netfilter.new/userspace/extensions/libip6t_rt.c --- netfilter/userspace/extensions/libip6t_rt.c Wed Apr 24 11:35:01 2002 +++ netfilter.new/userspace/extensions/libip6t_rt.c Sat Apr 27 00:05:24 2002 @@ -6,8 +6,14 @@ #include <getopt.h> #include <errno.h> #include <ip6tables.h> +/*#include <linux/in6.h>*/ #include <linux/netfilter_ipv6/ip6t_rt.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +/*#define DEBUG 1*/ + /* Function which prints out usage message. */ static void help(void) @@ -18,8 +24,9 @@ " --rt-segsleft [!] num[:num] match the Segments Left field (range)\n" " --rt-len [!] length total length of this header\n" " --rt-0-res check the reserved filed, too (type 0)\n" -" --rt-0-addrs Type=0 addresses (list) - NOT SUPPORTED, yet\n", -NETFILTER_VERSION); +" --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n" +" --rt-0-not-strict List of Type=0 addresses not a strict list\n", +NETFILTER_VERSION, IP6T_RT_HOPS); } static struct option opts[] = { @@ -27,7 +34,8 @@ { "rt-segsleft", 1, 0, '2' }, { "rt-len", 1, 0, '3' }, { "rt-0-res", 0, 0, '4' }, - { "rt-0-addrs", 0, 0, '5' }, + { "rt-0-addrs", 1, 0, '5' }, + { "rt-0-not-strict", 0, 0, '6' }, {0} }; @@ -74,6 +82,61 @@ free(buffer); } +static char * +addr_to_numeric(const struct in6_addr *addrp) +{ + static char buf[50+1]; + return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); +} + +static struct in6_addr * +numeric_to_addr(const char *num) +{ + static struct in6_addr ap; + int err; + + if ((err=inet_pton(AF_INET6, num, &ap)) == 1) + return ≈ +#ifdef DEBUG + fprintf(stderr, "\nnumeric2addr: %d\n", err); +#endif + exit_error(PARAMETER_PROBLEM, "bad address: %s", num); + + return (struct in6_addr *)NULL; +} + + +static int +parse_addresses(const char *addrstr, struct in6_addr *addrp) +{ + char *buffer, *cp, *next; + unsigned int i; + + buffer = strdup(addrstr); + if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed"); + + for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++) + { + next=strchr(cp, ','); + if (next) *next++='\0'; + memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr)); +#if DEBUG + printf("addr str: %s\n", cp); + printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp)))); + printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[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) @@ -86,6 +149,7 @@ rtinfo->hdrlen = 0; rtinfo->flags = 0; rtinfo->invflags = 0; + rtinfo->addrnr = 0; } /* Function which parses command options; returns true if it @@ -148,13 +212,25 @@ "Only one `--rt-0-addrs' allowed"); if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) exit_error(PARAMETER_PROBLEM, - "`--rt-type 0' required before `--rt-0-res'"); - /* TODO: implement it! */ - exit_error(PARAMETER_PROBLEM, - " `--rt-0-addrs' not supported, yet"); + "`--rt-type 0' required before `--rt-0-addrs'"); + check_inverse(optarg, &invert, &optind, 0); + if (invert) + exit_error(PARAMETER_PROBLEM, + " '!' not allowed with `--rt-0-addrs'"); + rtinfo->addrnr = parse_addresses(argv[optind-1], rtinfo->addrs); rtinfo->flags |= IP6T_RT_FST; *flags |= IP6T_RT_FST; break; + case '6': + if (*flags & IP6T_RT_FST_NSTRICT) + exit_error(PARAMETER_PROBLEM, + "Only one `--rt-0-not-strict' allowed"); + if ( !(*flags & IP6T_RT_FST) ) + exit_error(PARAMETER_PROBLEM, + "`--rt-0-addr ...' required before `--rt-0-not-strict'"); + rtinfo->flags |= IP6T_RT_FST_NSTRICT; + *flags |= IP6T_RT_FST_NSTRICT; + break; default: return 0; } @@ -189,6 +265,16 @@ } } +static void +print_addresses(int addrnr, struct in6_addr *addrp) +{ + unsigned int i; + + for(i=0; i<addrnr; i++){ + printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' '); + } +} + /* Prints out the union ip6t_matchinfo. */ static void print(const struct ip6t_ip6 *ip, @@ -209,7 +295,9 @@ printf(" "); } if (rtinfo->flags & IP6T_RT_RES) printf("reserved "); - if (rtinfo->flags & IP6T_RT_FST) printf("type0-addrs "); + if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs "); + print_addresses(rtinfo->addrnr, rtinfo->addrs); + if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict "); if (rtinfo->invflags & ~IP6T_RT_INV_MASK) printf("Unknown invflags: 0x%X ", rtinfo->invflags & ~IP6T_RT_INV_MASK); @@ -248,6 +336,8 @@ if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res "); if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs "); + print_addresses(rtinfo->addrnr, rtinfo->addrs); + if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict "); } diff -urN netfilter/userspace/patch-o-matic/base/route6.patch.ipv6 netfilter.new/userspace/patch-o-matic/base/route6.patch.ipv6 --- netfilter/userspace/patch-o-matic/base/route6.patch.ipv6 Wed Apr 24 11:35:01 2002 +++ netfilter.new/userspace/patch-o-matic/base/route6.patch.ipv6 Sat Apr 27 02:12:58 2002 @@ -1,10 +1,14 @@ diff -urN linux-2.4.18.hoi.1.1/include/linux/netfilter_ipv6/ip6t_rt.h linux/include/linux/netfilter_ipv6/ip6t_rt.h --- linux-2.4.18.hoi.1.1/include/linux/netfilter_ipv6/ip6t_rt.h Thu Jan 1 01:00:00 1970 +++ linux/include/linux/netfilter_ipv6/ip6t_rt.h Mon Apr 22 01:04:24 2002 -@@ -0,0 +1,34 @@ +@@ -0,0 +1,42 @@ +#ifndef _IP6T_RT_H +#define _IP6T_RT_H + ++/*#include <linux/in6.h>*/ ++ ++#define IP6T_RT_HOPS 16 ++ +struct ip6t_rt +{ + u_int32_t rt_type; /* Routing Type */ @@ -12,13 +16,17 @@ + u_int32_t hdrlen; /* Header Length */ + u_int8_t flags; /* */ + u_int8_t invflags; /* Inverse flags */ ++ struct in6_addr addrs[IP6T_RT_HOPS]; /* Hops */ ++ u_int8_t addrnr; /* Nr of Addresses */ +}; + +#define IP6T_RT_TYP 0x01 +#define IP6T_RT_SGS 0x02 +#define IP6T_RT_LEN 0x04 +#define IP6T_RT_RES 0x08 ++#define IP6T_RT_FST_MASK 0x30 +#define IP6T_RT_FST 0x10 ++#define IP6T_RT_FST_NSTRICT 0x20 + +/* Values for "invflags" field in struct ip6t_rt. */ +#define IP6T_RT_INV_TYP 0x01 /* Invert the sense of type. */ @@ -36,10 +44,10 @@ +#define MASK_PROTO 1 + +#endif /*_IP6T_RT_H*/ -diff -urN linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_rt.c linux-2.4.18/net/ipv6/netfilter/ip6t_rt.c +diff -urN linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_rt.c linux/net/ipv6/netfilter/ip6t_rt.c --- linux-2.4.18.hoi.1.1/net/ipv6/netfilter/ip6t_rt.c Thu Jan 1 01:00:00 1970 -+++ linux-2.4.18/net/ipv6/netfilter/ip6t_rt.c Mon Apr 22 02:55:04 2002 -@@ -0,0 +1,225 @@ ++++ linux/net/ipv6/netfilter/ip6t_rt.c Mon Apr 22 02:55:04 2002 +@@ -0,0 +1,305 @@ +/* Kernel module to match ROUTING parameters. */ +#include <linux/module.h> +#include <linux/skbuff.h> @@ -100,10 +108,11 @@ + struct ipv6_rt_hdr *route = NULL; + const struct ip6t_rt *rtinfo = matchinfo; + unsigned int temp; -+ int len; ++ unsigned int len; + u8 nexthdr; + unsigned int ptr; + unsigned int hdrlen = 0; ++ unsigned int ret = 0; + + /* type of the 1st exthdr */ + nexthdr = skb->nh.ipv6h->nexthdr; @@ -178,6 +187,11 @@ + return 0; + } + ++ if (len < hdrlen){ ++ /* Pcket smaller than its length field */ ++ return 0; ++ } ++ + route=skb->data+ptr; + + DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen); @@ -202,7 +216,7 @@ + (rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap, + !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap))); + -+ return (route != NULL) ++ ret = (route != NULL) + && + (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1], + ntohl(route->segments_left), @@ -217,6 +231,80 @@ + !!(rtinfo->invflags & IP6T_RT_INV_TYP))) + && + !((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)); ++ ++ DEBUGP("#%d ",rtinfo->addrnr); ++ temp = len = ptr = 0; ++ if ( !(rtinfo->flags & IP6T_RT_FST) ){ ++ return ret; ++ } else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) { ++ DEBUGP("Not strict "); ++ if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ ++ DEBUGP("There isn't enough space\n"); ++ return 0; ++ } else { ++ DEBUGP("#%d ",rtinfo->addrnr); ++ ptr = 0; ++ for(temp=0; temp<(unsigned int)((hdrlen-8)/16); temp++){ ++ len = 0; ++ while ((u8)(((struct rt0_hdr *)route)-> ++ addr[temp].s6_addr[len]) == ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])){ ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])); ++ len++; ++ if ( len == 16 ) break; ++ } ++ if (len==16) { ++ DEBUGP("ptr=%d temp=%d;\n",ptr,temp); ++ ptr++; ++ } else { ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[ptr].s6_addr[len])); ++ DEBUGP("!ptr=%d temp=%d;\n",ptr,temp); ++ } ++ if (ptr==rtinfo->addrnr) break; ++ } ++ DEBUGP("ptr=%d len=%d #%d\n",ptr,len, rtinfo->addrnr); ++ if ( (len == 16) && (ptr == rtinfo->addrnr)) ++ return ret; ++ else return 0; ++ } ++ } else { ++ DEBUGP("Strict "); ++ if ( rtinfo->addrnr > (unsigned int)((hdrlen-8)/16) ){ ++ DEBUGP("There isn't enough space\n"); ++ return 0; ++ } else { ++ DEBUGP("#%d ",rtinfo->addrnr); ++ for(temp=0; temp<rtinfo->addrnr; temp++){ ++ len = 0; ++ while ((u8)(((struct rt0_hdr *)route)-> ++ addr[temp].s6_addr[len]) == ++ (u8)(rtinfo->addrs[temp].s6_addr[len])){ ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[temp].s6_addr[len])); ++ len++; ++ if ( len == 16 ) break; ++ } ++ if (len!=16) { ++ DEBUGP("%02X?%02X ", ++ (u8)(((struct rt0_hdr *)route)->addr[temp].s6_addr[len]), ++ (u8)(rtinfo->addrs[temp].s6_addr[len])); ++ DEBUGP("!len=%d temp=%d;\n",len,temp); ++ break; ++ } ++ } ++ DEBUGP("temp=%d len=%d #%d\n",temp,len,rtinfo->addrnr); ++ if ( (len == 16) && (temp == rtinfo->addrnr) && (temp == (unsigned int)((hdrlen-8)/16))) ++ return ret; ++ else return 0; ++ } ++ } ++ ++ return 0; +} + +/* Called when user tries to insert an entry of this type. */ @@ -239,7 +327,7 @@ + rtinfo->invflags); + return 0; + } -+ if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST)) && ++ if ( (rtinfo->flags & (IP6T_RT_RES|IP6T_RT_FST_MASK)) && + (!(rtinfo->flags & IP6T_RT_TYP) || + (rtinfo->rt_type != 0) || + (rtinfo->invflags & IP6T_RT_INV_TYP)) ) { diff -urN netfilter/userspace/patch-o-matic/base/route6.patch.ipv6.help netfilter.new/userspace/patch-o-matic/base/route6.patch.ipv6.help --- netfilter/userspace/patch-o-matic/base/route6.patch.ipv6.help Wed Apr 24 11:35:01 2002 +++ netfilter.new/userspace/patch-o-matic/base/route6.patch.ipv6.help Sat Apr 27 02:09:55 2002 @@ -9,5 +9,6 @@ --rt-segsleft [!] num[:num] match the Segments Left field (range) --rt-len [!] length total length of this header --rt-0-res check the reserved filed, too (type 0) - --rt-0-addrs Type=0 addresses (list) - NOT SUPPORTED, yet + --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: 16) + --rt-0-not-strict List of Type=0 addresses not a strict list
--- netfilter.old/HOWTO/netfilter-extensions-HOWTO.sgml Sat Apr 27 02:18:16 2002 +++ netfilter/HOWTO/netfilter-extensions-HOWTO.sgml Sat Apr 27 02:38:44 2002 @@ -1197,6 +1197,108 @@ <p> This match hasn't got any option. +<sect1>ahesp6 patch +<p> +This patch by Andras Kis-Szabo <[EMAIL PROTECTED]> adds a new match +that allows you to match a packet based on its ah and esp headers' content. +The name of the matches: +<itemize> +<item>``ah'' : lets you match the IPv6 packet based on its ah header. +<item>``esp'' : lets you match the IPv6 packet based on its esp header. +</itemize> +<p> +Current status: base, works 4 me + +<p> +For example, we will drop all the AH packets that have a SPI equal to +500, and check the contents of the restricted area in the header : + +<tscreen><verb> +# ip6tables -A INPUT -m ah --ahspi 500 --ahres -j DROP + +# ip6tables --list +Chain INPUT (policy ACCEPT) +target prot opt source destination +DROP all anywhere anywhere ah spi:500 reserved +</verb></tscreen> + +<p> +Supported options for the ah match are : + +<descrip> +<tag>--ahspi [!] spi[:spi]</> -> match spi (range) +<tag>--ahlen [!] length</> -> length ot this header +<tag>--ahres </> -> checks the contents of the reserved field +</descrip> + +<p> +The esp match works exactly the same as in IPv4 : + +<tscreen><verb> +# ip6tables -A INPUT -m esp --espspi 500 -j DROP + +# iptables --list +Chain INPUT (policy ACCEPT) +target prot opt source destination +DROP all anywhere anywhere esp spi:500 +</verb></tscreen> + +<p> +Supported options for the esp match are : + +<descrip> +<tag>--espspi [!] spi[:spi]</> -> match spi (range) +</descrip> + +In IPv6 these matches can be concatenated: + +<tscreen><verb> +# ip6tables -A INPUT -m ah --ahspi 500 --ahres --ahlen ! 40 -m esp --espspi 500 -j +DROP + +# iptables --list +Chain INPUT (policy ACCEPT) +target prot opt source destination +DROP all anywhere anywhere ah spi:500 length:!40 +reserved esp spi:500 +</verb></tscreen> + +<sect1>frag6 patch +<p> +This patch by Andras Kis-Szabo <[EMAIL PROTECTED]> adds a new match +that allows you to match a packet based on the content of its fragmentation +header. +The name of the match: +<itemize> +<item>``frag'' : lets you match the IPv6 packet based on its fragmentation +header. +</itemize> +<p> +Current status: base, works 4 me + +<p> +For example, we will drop all the packets that have an ID between 100 and 200, +and the packet is the first fragment : + +<tscreen><verb> +# ip6tables -A INPUT -m frag --fragid 100:200 --fragfirst -j DROP + +# ip6tables --list +Chain INPUT (policy ACCEPT) +target prot opt source destination +DROP all anywhere anywhere frag ids:100:200 first +</verb></tscreen> + +<p> +Supported options for the frag match are : + +<descrip> +<tag>--fragid [!] id[:id]</> -> match the id (range) of the fragmenation +<tag>--fraglen [!] length</> -> match total length of this header +<tag>--fragres</> -> checks the contents of the reserved field +<tag>--fragfirst</> -> matches on the first fragment +<tag>--fragmore</> -> there are more fragments +<tag>--fraglast</> -> this is the last fragment +</descrip> + <sect1>ipv6header patch <p> This patch by Andras Kis-Szabo <[EMAIL PROTECTED]> adds a new match @@ -1206,7 +1308,7 @@ <item>``ipv6header'' : lets you match the IPv6 packet based on its headers. </itemize> <p> -Current status: base, highly experimental +Current status: base, works 4 me <p> For example, let's drop the packets which have got hop-by-hop, ipv6-route @@ -1295,69 +1397,44 @@ Values of the range not present will be implied. The implied value for minimum is 0, and for maximum is 65535. -<sect1>ahesp6 patch +<sect1>route6 patch <p> This patch by Andras Kis-Szabo <[EMAIL PROTECTED]> adds a new match -that allows you to match a packet based on its ah and esp headers' content. -The name of the matches: +that allows you to match a packet based on the content of its routing +header. +The name of the match: <itemize> -<item>``ah'' : lets you match the IPv6 packet based on its ah header. -<item>``esp'' : lets you match the IPv6 packet based on its esp header. +<item>``rt'' : lets you match the IPv6 packet based on its routing +header. </itemize> <p> -Current status: base, highly experimental +Current status: base, works 4 me <p> -For example, we will drop all the AH packets that have a SPI equal to -500, and check the contents of the restricted area in the header : +For example, we will drop all the packets that have 0 routing type, the packet +is near the last hop (max 2 hops far), the routing path contains ::1 and ::2 +(but not exactly): <tscreen><verb> -# ip6tables -A INPUT -m ah --ahspi 500 --ahres -j DROP +# ip6tables -A INPUT -m rt --rt-type 0 --rt-segsleft :2 --rt-0-addrs ::1,::2 +--rt-0-not-strict -j DROP # ip6tables --list Chain INPUT (policy ACCEPT) target prot opt source destination -DROP all anywhere anywhere ah spi:500 reserved +DROP all anywhere anywhere rt type:0 segslefts:0:2 +0-addrs ::1,::2 0-not-strict </verb></tscreen> <p> -Supported options for the ah match are : +Supported options for the rt match are : <descrip> -<tag>--ahspi [!] spi[:spi]</> -> match spi (range) -<tag>--ahlen [!] length</> -> length ot this header -<tag>--ahres </> -> check the contents of the reserved field +<tag>--rt-type [!] type</> -> matches the type +<tag>--rt-segsleft [!] num[:num]</> -> matches the Segments Left field (range) +<tag>--rt-len [!] length</> -> total length of this header +<tag>--rt-0-res</> -> checks the contents of the reserved field +<tag>--rt-0-addrs ADDR[,ADDR...]</> -> Type=0 addresses (list, max: 16) +<tag>--rt-0-not-strict</> -> List of Type=0 addresses not a strict list </descrip> - -<p> -The esp match works exactly the same as in IPv4 : - -<tscreen><verb> -# ip6tables -A INPUT -m esp --espspi 500 -j DROP - -# iptables --list -Chain INPUT (policy ACCEPT) -target prot opt source destination -DROP all anywhere anywhere esp spi:500 -</verb></tscreen> - -<p> -Supported options for the esp match are : - -<descrip> -<tag>--espspi [!] spi[:spi]</> -> match spi (range) -</descrip> - -In IPv6 these matches can be concatenated: - -<tscreen><verb> -# ip6tables -A INPUT -m ah --ahspi 500 --ahres --ahlen ! 40 -m esp --espspi 500 -j DROP - -# iptables --list -Chain INPUT (policy ACCEPT) -target prot opt source destination -DROP all anywhere anywhere ah spi:500 length:!40 reserved esp spi:500 -</verb></tscreen> <sect>New IPv6 netfilter targets <p>