#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h>
-#define LOW(n) (n & 0x00FF)
-
#define HOPBYHOP 1
MODULE_LICENSE("GPL");
* 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
*/
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;
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;
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
- struct ipv6_opt_hdr *hdr;
+ struct ipv6_opt_hdr _hdr, *hp;
DEBUGP("ipv6_opts header iteration \n");
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
break;
}
- nexthdr = hdr->nexthdr;
+ nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if ( ptr > skb->len ) {
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,
((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) ){
DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; 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;