X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv6%2Fnetfilter%2Fip6t_dst.c;h=540925e4a7a80161f87757e82d640938f7e90e9d;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=2d385038c6638f1b559a55f3947deb3792bee612;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index 2d385038c..540925e4a 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c @@ -7,7 +7,6 @@ * published by the Free Software Foundation. */ - #include #include #include @@ -20,8 +19,6 @@ #include #include -#define LOW(n) (n & 0x00FF) - #define HOPBYHOP 0 MODULE_LICENSE("GPL"); @@ -48,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo "); * 0 -> invariant * 1 -> can change the routing * (Type & 0x1F) Type - * 0 -> PAD0 (only 1 byte!) - * 1 -> PAD1 LENGTH info (total length = length + 2) + * 0 -> Pad1 (only 1 byte!) + * 1 -> PadN LENGTH info (total length = length + 2) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * 5 -> RTALERT 2 x x */ @@ -60,11 +57,10 @@ match(const struct sk_buff *skb, const struct net_device *out, const void *matchinfo, int offset, - const void *protohdr, - u_int16_t datalen, + unsigned int protoff, int *hotdrop) { - struct ipv6_opt_hdr *optsh = NULL; + struct ipv6_opt_hdr _optsh, *oh; const struct ip6t_opts *optinfo = matchinfo; unsigned int temp; unsigned int len; @@ -72,7 +68,9 @@ match(const struct sk_buff *skb, unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; - u_int16_t *optdesc = NULL; + u8 _opttype, *tp = NULL; + u8 _optlen, *lp = NULL; + unsigned int optlen; /* type of the 1st exthdr */ nexthdr = skb->nh.ipv6h->nexthdr; @@ -83,7 +81,7 @@ match(const struct sk_buff *skb, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr *hdr; + struct ipv6_opt_hdr _hdr, *hp; DEBUGP("ipv6_opts header iteration \n"); @@ -99,15 +97,16 @@ match(const struct sk_buff *skb, break; } - hdr=(void *)(skb->data)+ptr; + hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); + BUG_ON(hp == NULL); /* Calculate the header length */ if (nexthdr == NEXTHDR_FRAGMENT) { hdrlen = 8; } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hdr->hdrlen+2)<<2; + hdrlen = (hp->hdrlen+2)<<2; else - hdrlen = ipv6_optlen(hdr); + hdrlen = ipv6_optlen(hp); /* OPTS -> evaluate */ #if HOPBYHOP @@ -135,7 +134,7 @@ match(const struct sk_buff *skb, break; } - nexthdr = hdr->nexthdr; + nexthdr = hp->nexthdr; len -= hdrlen; ptr += hdrlen; if ( ptr > skb->len ) { @@ -161,9 +160,10 @@ match(const struct sk_buff *skb, return 0; } - optsh=(void *)(skb->data)+ptr; + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + BUG_ON(oh == NULL); - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); + DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); DEBUGP("len %02X %04X %02X ", optinfo->hdrlen, hdrlen, @@ -171,13 +171,12 @@ match(const struct sk_buff *skb, ((optinfo->hdrlen == hdrlen) ^ !!(optinfo->invflags & IP6T_OPTS_INV_LEN)))); - ret = (optsh != NULL) + ret = (oh != 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) ){ @@ -188,48 +187,59 @@ match(const struct sk_buff *skb, DEBUGP("Strict "); DEBUGP("#%d ",optinfo->optsnr); for(temp=0; tempoptsnr; temp++){ - optdesc = (void *)(skb->data)+ptr; + /* type field exists ? */ + if (hdrlen < 1) + break; + tp = skb_header_pointer(skb, ptr, sizeof(_opttype), + &_opttype); + if (tp == NULL) + break; + /* Type check */ - if ( (unsigned char)*optdesc != - (optinfo->opts[temp] & 0xFF00)>>8 ){ + if (*tp != (optinfo->opts[temp] & 0xFF00)>>8){ DEBUGP("Tbad %02X %02X\n", - (unsigned char)*optdesc, - (optinfo->opts[temp] & - 0xFF00)>>8); + *tp, + (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]); + if (*tp) { + u16 spec_len; + + /* length field exists ? */ + if (hdrlen < 2) + break; + lp = skb_header_pointer(skb, ptr + 1, + sizeof(_optlen), + &_optlen); + if (lp == NULL) + break; + spec_len = optinfo->opts[temp] & 0x00FF; + + if (spec_len != 0x00FF && spec_len != *lp) { + DEBUGP("Lbad %02X %04X\n", *lp, + spec_len); return 0; - } else { - DEBUGP("Lok "); } - } - /* Step to the next */ - if ((unsigned char)*optdesc == 0){ - DEBUGP("PAD0 \n"); - ptr++; - hdrlen--; + DEBUGP("Lok "); + optlen = *lp + 2; } else { - ptr += LOW(ntohs(*optdesc)); - hdrlen -= LOW(ntohs(*optdesc)); - DEBUGP("len%04X \n", - LOW(ntohs(*optdesc))); + DEBUGP("Pad1\n"); + optlen = 1; } - if (ptr > skb->len || ( !hdrlen && - (temp != optinfo->optsnr - 1))) { + + /* Step to the next */ + DEBUGP("len%04X \n", optlen); + + if ((ptr > skb->len - optlen || hdrlen < optlen) && + (temp < optinfo->optsnr - 1)) { DEBUGP("new pointer is too large! \n"); break; } + ptr += optlen; + hdrlen -= optlen; } if (temp == optinfo->optsnr) return ret; @@ -271,6 +281,7 @@ static struct ip6t_match opts_match = { #endif .match = &match, .checkentry = &checkentry, + .me = THIS_MODULE, }; static int __init init(void)