static void ipsec6_input_get_offset(u8 *packet, u32 packet_len, struct inet6_skb_parm* opt)
{
	u16 offset = sizeof(struct ipv6hdr);
	u8 nexthdr = ((struct ipv6hdr*)packet)->nexthdr;
	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(packet + offset);

	while (offset + 1 < packet_len) {

		switch (nexthdr) {

		case NEXTHDR_HOP:
			opt->hop = offset;
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
			break;

		case NEXTHDR_ROUTING:
			if (opt->dst1) {
				opt->dst0 = opt->dst1;
				opt->dst1 = 0;
			}
			opt->srcrt = offset;
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
			break;

		case NEXTHDR_DEST:
			opt->dst1 = offset;
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
			break;

		case NEXTHDR_AUTH:
			opt->auth = offset;
			offset += (exthdr->hdrlen + 2) <<2;
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(packet + offset);
			break;

		default :
			return;
		}
	}

	return;
}
int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
			   int len)
{
	u8 nexthdr = *nexthdrp;

	while (ipv6_ext_hdr(nexthdr)) {
		struct ipv6_opt_hdr hdr;
		int hdrlen;

		if (len < (int)sizeof(struct ipv6_opt_hdr))
			return -1;
		if (nexthdr == NEXTHDR_NONE)
			break;
		if (nexthdr == NEXTHDR_FRAGMENT)
			break;
		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
			BUG();
		if (nexthdr == NEXTHDR_AUTH)
			hdrlen = (hdr.hdrlen+2)<<2;
		else
			hdrlen = ipv6_optlen(&hdr);

		nexthdr = hdr.nexthdr;
		len -= hdrlen;
		start += hdrlen;
	}

	*nexthdrp = nexthdr;
	return start;
}
Beispiel #3
0
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
	u16 offset = sizeof(struct ipv6hdr);
	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
	unsigned int packet_len = skb->tail - skb->nh.raw;
	int found_rhdr = 0;
	*nexthdr = &skb->nh.ipv6h->nexthdr;

	while (offset + 1 <= packet_len) {

		switch (**nexthdr) {

		case NEXTHDR_HOP:
		case NEXTHDR_ROUTING:
		case NEXTHDR_DEST:
			if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1;
			if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset;
			offset += ipv6_optlen(exthdr);
			*nexthdr = &exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
			break;
		default :
			return offset;
		}
	}

	return offset;
}
Beispiel #4
0
static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
{
	const struct net_offload *ops = NULL;

	for (;;) {
		struct ipv6_opt_hdr *opth;
		int len;

		if (proto != NEXTHDR_HOP) {
			ops = rcu_dereference(inet6_offloads[proto]);

			if (unlikely(!ops))
				break;

			if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
				break;
		}

		if (unlikely(!pskb_may_pull(skb, 8)))
			break;

		opth = (void *)skb->data;
		len = ipv6_optlen(opth);

		if (unlikely(!pskb_may_pull(skb, len)))
			break;

		opth = (void *)skb->data;
		proto = opth->nexthdr;
		__skb_pull(skb, len);
	}

	return proto;
}
Beispiel #5
0
/* Return the total length of all the extension hdrs, following the same
 * logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs.
 */
static int ipv6_exthdrs_len(struct ipv6hdr *iph,
			    const struct net_offload **opps)
{
	struct ipv6_opt_hdr *opth = NULL;
	int len = 0, proto, optlen;

	proto = iph->nexthdr;
	for (;;) {
		if (proto != NEXTHDR_HOP) {
			*opps = rcu_dereference(inet6_offloads[proto]);
			if (unlikely(!(*opps)))
				break;
			if (!((*opps)->flags & INET6_PROTO_GSO_EXTHDR))
				break;
		}
		if (opth == NULL)
			opth = (void *)(iph+1);
		else
			opth = (void *)opth + optlen;
		optlen = ipv6_optlen(opth);
		len += optlen;
		proto = opth->nexthdr;
	}
	return len;
}
Beispiel #6
0
static bool dns_mt6(const struct sk_buff *skb, XT_PARAM *par) {
    struct ipv6hdr _iph;
    const struct ipv6hdr *ih;
    int16_t ptr;

    struct ipv6_opt_hdr _hdr;
    const struct ipv6_opt_hdr *hp;

    uint8_t currenthdr;
    uint16_t hdrlen = 0;

    if (par->fragoff != 0) {
        DEBUG_PRINT("fragment packet");
        return false;
    }

    DEBUG_PRINT("start ipv6");

    ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
    ptr = sizeof(_iph);

    currenthdr = ih->nexthdr;
    DEBUG_PRINT("start opt loop");
    while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
        DEBUG_PRINT("optloop %u", currenthdr);
        hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
        if (hp == NULL) {
            return false;
        }
        switch (currenthdr) {
        case IPPROTO_FRAGMENT:
            hdrlen = 8;
            break;
        case IPPROTO_DSTOPTS:
        case IPPROTO_ROUTING:
        case IPPROTO_HOPOPTS:
            hdrlen = ipv6_optlen(hp);
            break;
        case IPPROTO_AH:
            hdrlen = (hp->hdrlen + 2) << 2;
            break;
        }
        currenthdr = hp->nexthdr;
        ptr += hdrlen;
    }
    if (currenthdr == IPPROTO_UDP) {
        return dns_mt_udp(skb, par, ptr);
    }
    if (currenthdr == IPPROTO_TCP) {
        return dns_mt_tcp(skb, par, ptr);
    }
    DEBUG_PRINT("unsupported protocol.");
    return false;
}
/**
 *	ipv6_rearrange_destopt - rearrange IPv6 destination options header
 *	@iph: IPv6 header
 *	@destopt: destionation options header
 */
static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt)
{
	u8 *opt = (u8 *)destopt;
	int len = ipv6_optlen(destopt);
	int off = 0;
	int optlen = 0;

	off += 2;
	len -= 2;

	while (len > 0) {

		switch (opt[off]) {

		case IPV6_TLV_PAD0:
			optlen = 1;
			break;
		default:
			if (len < 2)
				goto bad;
			optlen = opt[off+1]+2;
			if (len < optlen)
				goto bad;

			/* Rearrange the source address in @iph and the
			 * addresses in home address option for final source.
			 * See 11.3.2 of RFC 3775 for details.
			 */
			if (opt[off] == IPV6_TLV_HAO) {
				struct in6_addr final_addr;
				struct ipv6_destopt_hao *hao;

				hao = (struct ipv6_destopt_hao *)&opt[off];
				if (hao->length != sizeof(hao->addr)) {
					if (net_ratelimit())
						printk(KERN_WARNING "destopt hao: invalid header length: %u\n", hao->length);
					goto bad;
				}
				ipv6_addr_copy(&final_addr, &hao->addr);
				ipv6_addr_copy(&hao->addr, &iph->saddr);
				ipv6_addr_copy(&iph->saddr, &final_addr);
			}
			break;
		}

		off += optlen;
		len -= optlen;
	}
	/* Note: ok if len == 0 */
bad:
	return;
}
static __u16
parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
{
	struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
	__u8 nexthdr = ipv6h->nexthdr;
	__u16 off = sizeof (*ipv6h);

	while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
		__u16 optlen = 0;
		struct ipv6_opt_hdr *hdr;
		if (raw + off + sizeof (*hdr) > skb->data &&
		    !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
			break;

		hdr = (struct ipv6_opt_hdr *) (raw + off);
		if (nexthdr == NEXTHDR_FRAGMENT) {
			struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
			if (frag_hdr->frag_off)
				break;
			optlen = 8;
		} else if (nexthdr == NEXTHDR_AUTH) {
			optlen = (hdr->hdrlen + 2) << 2;
		} else {
			optlen = ipv6_optlen(hdr);
		}
		if (nexthdr == NEXTHDR_DEST) {
			__u16 i = off + 2;
			while (1) {
				struct ipv6_tlv_tnl_enc_lim *tel;

				/* No more room for encapsulation limit */
				if (i + sizeof (*tel) > off + optlen)
					break;

				tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
				/* return index of option if found and valid */
				if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
				    tel->length == 1)
					return i;
				/* else jump to next option */
				if (tel->type)
					i += tel->length + 2;
				else
					i++;
			}
		}
		nexthdr = hdr->nexthdr;
		off += optlen;
	}
	return 0;
}
/*
 * find the header just before Fragment Header.
 *
 * if success return 0 and set ...
 * (*prevhdrp): the value of "Next Header Field" in the header
 *		just before Fragment Header.
 * (*prevhoff): the offset of "Next Header Field" in the header
 *		just before Fragment Header.
 * (*fhoff)   : the offset of Fragment Header.
 *
 * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c
 *
 */
static int
find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
{
        u8 nexthdr = skb->nh.ipv6h->nexthdr;
	u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;
	int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;
	int len = skb->len - start;
	u8 prevhdr = NEXTHDR_IPV6;

        while (nexthdr != NEXTHDR_FRAGMENT) {
                struct ipv6_opt_hdr hdr;
                int hdrlen;

		if (!ipv6_ext_hdr(nexthdr)) {
			return -1;
		}
                if (len < (int)sizeof(struct ipv6_opt_hdr)) {
			DEBUGP("too short\n");
			return -1;
		}
                if (nexthdr == NEXTHDR_NONE) {
			DEBUGP("next header is none\n");
			return -1;
		}
                if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
                        BUG();
                if (nexthdr == NEXTHDR_AUTH)
                        hdrlen = (hdr.hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(&hdr);

		prevhdr = nexthdr;
		prev_nhoff = start;

                nexthdr = hdr.nexthdr;
                len -= hdrlen;
                start += hdrlen;
        }

	if (len < 0)
		return -1;

	*prevhdrp = prevhdr;
	*prevhoff = prev_nhoff;
	*fhoff = start;

	return 0;
}
static inline void
_decode_session6(struct sk_buff *skb, struct flowi *fl)
{
	u16 offset = sizeof(struct ipv6hdr);
	struct ipv6hdr *hdr = skb->nh.ipv6h;
	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
	u8 nexthdr = skb->nh.ipv6h->nexthdr;

	memset(fl, 0, sizeof(struct flowi));
	ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr);
	ipv6_addr_copy(&fl->fl6_src, &hdr->saddr);

	while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) {
		switch (nexthdr) {
		case NEXTHDR_ROUTING:
		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
			break;

		case IPPROTO_UDP:
		case IPPROTO_TCP:
		case IPPROTO_SCTP:
			if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) {
				u16 *ports = (u16 *)exthdr;

				fl->fl_ip_sport = ports[0];
				fl->fl_ip_dport = ports[1];
			}
			fl->proto = nexthdr;
			return;

		/* XXX Why are there these headers? */
		case IPPROTO_AH:
		case IPPROTO_ESP:
		case IPPROTO_COMP:
		default:
			fl->fl_ipsec_spi = 0;
			fl->proto = nexthdr;
			return;
		};
	}
}
Beispiel #11
0
static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
{
	union {
		struct ipv6hdr *iph;
		struct ipv6_opt_hdr *opth;
		struct ipv6_rt_hdr *rth;
		char *raw;
	} exthdr = { .iph = iph };
	char *end = exthdr.raw + len;
	int nexthdr = iph->nexthdr;

	exthdr.iph++;

	while (exthdr.raw < end) {
		switch (nexthdr) {
		case NEXTHDR_DEST:
#ifdef CONFIG_IPV6_MIP6
			if (dir == XFRM_POLICY_OUT)
				ipv6_rearrange_destopt(iph, exthdr.opth);
#endif
		case NEXTHDR_HOP:
			if (!zero_out_mutable_opts(exthdr.opth)) {
				LIMIT_NETDEBUG(
					KERN_WARNING "overrun %sopts\n",
					nexthdr == NEXTHDR_HOP ?
						"hop" : "dest");
				return -EINVAL;
			}
			break;

		case NEXTHDR_ROUTING:
			ipv6_rearrange_rthdr(iph, exthdr.rth);
			break;

		default :
			return 0;
		}

		nexthdr = exthdr.opth->nexthdr;
		exthdr.raw += ipv6_optlen(exthdr.opth);
	}

	return 0;
}
Beispiel #12
0
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
	u16 offset = sizeof(struct ipv6hdr);
	struct ipv6_opt_hdr *exthdr =
				(struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
	unsigned int packet_len = skb_tail_pointer(skb) -
		skb_network_header(skb);
	int found_rhdr = 0;
	*nexthdr = &ipv6_hdr(skb)->nexthdr;

	while (offset + 1 <= packet_len) {

		switch (**nexthdr) {

		case NEXTHDR_HOP:
			break;
		case NEXTHDR_ROUTING:
			found_rhdr = 1;
			break;
		case NEXTHDR_DEST:
#if IS_ENABLED(CONFIG_IPV6_MIP6)
			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
				break;
#endif
			if (found_rhdr)
				return offset;
			break;
		default :
			return offset;
		}

		offset += ipv6_optlen(exthdr);
		*nexthdr = &exthdr->nexthdr;
		exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
						 offset);
	}

	return offset;
}
Beispiel #13
0
static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
{
	u8 *opt = (u8 *)opthdr;
	int len = ipv6_optlen(opthdr);
	int off = 0;
	int optlen = 0;

	off += 2;
	len -= 2;

	while (len > 0) {

		switch (opt[off]) {

		case IPV6_TLV_PAD0:
			optlen = 1;
			break;
		default:
			if (len < 2) 
				goto bad;
			optlen = opt[off+1]+2;
			if (len < optlen)
				goto bad;
			if (opt[off] & 0x20)
				memset(&opt[off+2], 0, opt[off+1]);
			break;
		}

		off += optlen;
		len -= optlen;
	}
	if (len == 0)
		return 1;

bad:
	return 0;
}
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
{
	u16 offset = sizeof(struct ipv6hdr);
	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
	unsigned int packet_len = skb->tail - skb->nh.raw;
	int found_rhdr = 0;
	*nexthdr = &skb->nh.ipv6h->nexthdr;

	while (offset + 1 <= packet_len) {

		switch (**nexthdr) {

		case NEXTHDR_HOP:
			break;
		case NEXTHDR_ROUTING:
			found_rhdr = 1;
			break;
		case NEXTHDR_DEST:
#ifdef CONFIG_IPV6_MIP6
			if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
				break;
#endif
			if (found_rhdr)
				return offset;
			break;
		default :
			return offset;
		}

		offset += ipv6_optlen(exthdr);
		*nexthdr = &exthdr->nexthdr;
		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
	}

	return offset;
}
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_rt_hdr *route = NULL;
       const struct ip6t_rt *rtinfo = matchinfo;
       unsigned int temp;
       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;
       /* pointer to the 1st exthdr */
       ptr = sizeof(struct ipv6hdr);
       /* available length */
       len = skb->len - ptr;
       temp = 0;

        while (ip6t_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr *hdr;

              DEBUGP("ipv6_rt 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=(struct ipv6_opt_hdr *)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);

              /* ROUTING -> evaluate */
                if (nexthdr == NEXTHDR_ROUTING) {
                     temp |= MASK_ROUTING;
                     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_rt match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_rt: new pointer is too large! \n");
			break;
		}
        }

       /* ROUTING header not found */
       if ( temp != MASK_ROUTING ) return 0;

       if (len < (int)sizeof(struct ipv6_rt_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       if (len < hdrlen){
	       /* Pcket smaller than its length field */
       		return 0;
       }

       route = (struct ipv6_rt_hdr *) (skb->data + ptr);

       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
       DEBUGP("TYPE %04X ", route->type);
       DEBUGP("SGS_LEFT %u %08X\n", ntohl(route->segments_left), ntohl(route->segments_left));

       DEBUGP("IPv6 RT segsleft %02X ",
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
       DEBUGP("type %02X %02X %02X ",
       		rtinfo->rt_type, route->type, 
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
       DEBUGP("len %02X %04X %02X ",
       		rtinfo->hdrlen, hdrlen,
       		(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
       DEBUGP("res %02X %02X %02X ", 
       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)route)->bitmap,
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)route)->bitmap)));

       ret = (route != NULL)
       		&&
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           ntohl(route->segments_left),
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
		&&
	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
		&&
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == route->type) ^
                           !!(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;
}
Beispiel #16
0
static bool
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const struct xt_match *match,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      bool *hotdrop)
{
	struct ipv6_rt_hdr _route;
	const struct ipv6_rt_hdr *rh;
	const struct ip6t_rt *rtinfo = matchinfo;
	unsigned int temp;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	bool ret = false;
	struct in6_addr _addr;
	const struct in6_addr *ap;
	int err;

	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*hotdrop = true;
		return false;
	}

	rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
	if (rh == NULL) {
		*hotdrop = true;
		return false;
	}

	hdrlen = ipv6_optlen(rh);
	if (skb->len - ptr < hdrlen) {
		/* Pcket smaller than its length field */
		return false;
	}

	DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
	DEBUGP("TYPE %04X ", rh->type);
	DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);

	DEBUGP("IPv6 RT segsleft %02X ",
	       (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			       rh->segments_left,
			       !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
	DEBUGP("type %02X %02X %02X ",
	       rtinfo->rt_type, rh->type,
	       (!(rtinfo->flags & IP6T_RT_TYP) ||
		((rtinfo->rt_type == rh->type) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
	DEBUGP("len %02X %04X %02X ",
	       rtinfo->hdrlen, hdrlen,
	       (!(rtinfo->flags & IP6T_RT_LEN) ||
		((rtinfo->hdrlen == hdrlen) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
	DEBUGP("res %02X %02X %02X ",
	       (rtinfo->flags & IP6T_RT_RES),
	       ((const struct rt0_hdr *)rh)->reserved,
	       !((rtinfo->flags & IP6T_RT_RES) &&
		 (((const struct rt0_hdr *)rh)->reserved)));

	ret = (rh != NULL)
	      &&
	      (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			      rh->segments_left,
			      !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_LEN) ||
	       ((rtinfo->hdrlen == hdrlen) ^
		!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_TYP) ||
	       ((rtinfo->rt_type == rh->type) ^
		!!(rtinfo->invflags & IP6T_RT_INV_TYP)));

	if (ret && (rtinfo->flags & IP6T_RT_RES)) {
		const u_int32_t *rp;
		u_int32_t _reserved;
		rp = skb_header_pointer(skb,
					ptr + offsetof(struct rt0_hdr,
						       reserved),
					sizeof(_reserved),
					&_reserved);

		ret = (*rp == 0);
	}

	DEBUGP("#%d ", rtinfo->addrnr);
	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 false;
		} else {
			unsigned int i = 0;

			DEBUGP("#%d ", rtinfo->addrnr);
			for (temp = 0;
			     temp < (unsigned int)((hdrlen - 8) / 16);
			     temp++) {
				ap = skb_header_pointer(skb,
							ptr
							+ sizeof(struct rt0_hdr)
							+ temp * sizeof(_addr),
							sizeof(_addr),
							&_addr);

				BUG_ON(ap == NULL);

				if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
					DEBUGP("i=%d temp=%d;\n", i, temp);
					i++;
				}
				if (i == rtinfo->addrnr)
					break;
			}
			DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
			if (i == rtinfo->addrnr)
				return ret;
			else
				return false;
		}
	} else {
		DEBUGP("Strict ");
		if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
			DEBUGP("There isn't enough space\n");
			return false;
		} else {
			DEBUGP("#%d ", rtinfo->addrnr);
			for (temp = 0; temp < rtinfo->addrnr; temp++) {
				ap = skb_header_pointer(skb,
							ptr
							+ sizeof(struct rt0_hdr)
							+ temp * sizeof(_addr),
							sizeof(_addr),
							&_addr);
				BUG_ON(ap == NULL);

				if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp]))
					break;
			}
			DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
			if ((temp == rtinfo->addrnr) &&
			    (temp == (unsigned int)((hdrlen - 8) / 16)))
				return ret;
			else
				return false;
		}
	}

	return false;
}
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 frag_hdr *frag = NULL;
       const struct ip6t_frag *fraginfo = matchinfo;
       unsigned int temp;
       int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;

       /* 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_frag 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=(struct ipv6_opt_hdr *)(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);

              /* FRAG -> evaluate */
                if (nexthdr == NEXTHDR_FRAGMENT) {
                     temp |= MASK_FRAGMENT;
                     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_frag match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_frag: new pointer too large! \n");
			break;
		}
        }

       /* FRAG header not found */
       if ( temp != MASK_FRAGMENT ) return 0;

       if (len < sizeof(struct frag_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       frag = (struct frag_hdr *) (skb->data + ptr);

       DEBUGP("INFO %04X ", frag->frag_off);
       DEBUGP("OFFSET %04X ", ntohs(frag->frag_off) & ~0x7);
       DEBUGP("RES %02X %04X", frag->reserved, ntohs(frag->frag_off) & 0x6);
       DEBUGP("MF %04X ", frag->frag_off & htons(IP6_MF));
       DEBUGP("ID %u %08X\n", ntohl(frag->identification),
	      ntohl(frag->identification));

       DEBUGP("IPv6 FRAG id %02X ",
       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
                           ntohl(frag->identification),
                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
       DEBUGP("res %02X %02X%04X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_RES), frag->reserved,
		ntohs(frag->frag_off) & 0x6,
       		!((fraginfo->flags & IP6T_FRAG_RES)
			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6))));
       DEBUGP("first %02X %02X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_FST),
		ntohs(frag->frag_off) & ~0x7,
       		!((fraginfo->flags & IP6T_FRAG_FST)
			&& (ntohs(frag->frag_off) & ~0x7)));
       DEBUGP("mf %02X %02X %02X ", 
       		(fraginfo->flags & IP6T_FRAG_MF),
		ntohs(frag->frag_off) & IP6_MF,
       		!((fraginfo->flags & IP6T_FRAG_MF)
			&& !((ntohs(frag->frag_off) & IP6_MF))));
       DEBUGP("last %02X %02X %02X\n", 
       		(fraginfo->flags & IP6T_FRAG_NMF),
		ntohs(frag->frag_off) & IP6_MF,
       		!((fraginfo->flags & IP6T_FRAG_NMF)
			&& (ntohs(frag->frag_off) & IP6_MF)));

       return (frag != NULL)
       		&&
       		(id_match(fraginfo->ids[0], fraginfo->ids[1],
			  ntohl(frag->identification),
                           !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
		&&
		!((fraginfo->flags & IP6T_FRAG_RES)
			&& (frag->reserved || (ntohs(frag->frag_off) & 0x6)))
		&&
		!((fraginfo->flags & IP6T_FRAG_FST)
			&& (ntohs(frag->frag_off) & ~0x7))
		&&
		!((fraginfo->flags & IP6T_FRAG_MF)
			&& !(ntohs(frag->frag_off) & IP6_MF))
		&&
		!((fraginfo->flags & IP6T_FRAG_NMF)
			&& (ntohs(frag->frag_off) & IP6_MF));
}
Beispiel #18
0
/* One level of recursion won't kill us */
static void dump_ipv6_packet(struct sbuff *m,
			const struct nf_loginfo *info,
			const struct sk_buff *skb, unsigned int ip6hoff,
			int recurse)
{
	u_int8_t currenthdr;
	int fragment;
	struct ipv6hdr _ip6h;
	const struct ipv6hdr *ih;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	unsigned int logflags;

	if (info->type == NF_LOG_TYPE_LOG)
		logflags = info->u.log.logflags;
	else
		logflags = NF_LOG_MASK;

	ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
	if (ih == NULL) {
		sb_add(m, "TRUNCATED");
		return;
	}

	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
	sb_add(m, "SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);

	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
	sb_add(m, "LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
	       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
	       ih->hop_limit,
	       (ntohl(*(__be32 *)ih) & 0x000fffff));

	fragment = 0;
	ptr = ip6hoff + sizeof(struct ipv6hdr);
	currenthdr = ih->nexthdr;
	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
		struct ipv6_opt_hdr _hdr;
		const struct ipv6_opt_hdr *hp;

		hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
		if (hp == NULL) {
			sb_add(m, "TRUNCATED");
			return;
		}

		/* Max length: 48 "OPT (...) " */
		if (logflags & XT_LOG_IPOPT)
			sb_add(m, "OPT ( ");

		switch (currenthdr) {
		case IPPROTO_FRAGMENT: {
			struct frag_hdr _fhdr;
			const struct frag_hdr *fh;

			sb_add(m, "FRAG:");
			fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
						&_fhdr);
			if (fh == NULL) {
				sb_add(m, "TRUNCATED ");
				return;
			}

			/* Max length: 6 "65535 " */
			sb_add(m, "%u ", ntohs(fh->frag_off) & 0xFFF8);

			/* Max length: 11 "INCOMPLETE " */
			if (fh->frag_off & htons(0x0001))
				sb_add(m, "INCOMPLETE ");

			sb_add(m, "ID:%08x ", ntohl(fh->identification));

			if (ntohs(fh->frag_off) & 0xFFF8)
				fragment = 1;

			hdrlen = 8;

			break;
		}
		case IPPROTO_DSTOPTS:
		case IPPROTO_ROUTING:
		case IPPROTO_HOPOPTS:
			if (fragment) {
				if (logflags & XT_LOG_IPOPT)
					sb_add(m, ")");
				return;
			}
			hdrlen = ipv6_optlen(hp);
			break;
		/* Max Length */
		case IPPROTO_AH:
			if (logflags & XT_LOG_IPOPT) {
				struct ip_auth_hdr _ahdr;
				const struct ip_auth_hdr *ah;

				/* Max length: 3 "AH " */
				sb_add(m, "AH ");

				if (fragment) {
					sb_add(m, ")");
					return;
				}

				ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
							&_ahdr);
				if (ah == NULL) {
					/*
					 * Max length: 26 "INCOMPLETE [65535
					 *  bytes] )"
					 */
					sb_add(m, "INCOMPLETE [%u bytes] )",
					       skb->len - ptr);
					return;
				}

				/* Length: 15 "SPI=0xF1234567 */
				sb_add(m, "SPI=0x%x ", ntohl(ah->spi));

			}

			hdrlen = (hp->hdrlen+2)<<2;
			break;
		case IPPROTO_ESP:
			if (logflags & XT_LOG_IPOPT) {
				struct ip_esp_hdr _esph;
				const struct ip_esp_hdr *eh;

				/* Max length: 4 "ESP " */
				sb_add(m, "ESP ");

				if (fragment) {
					sb_add(m, ")");
					return;
				}

				/*
				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
				 */
				eh = skb_header_pointer(skb, ptr, sizeof(_esph),
							&_esph);
				if (eh == NULL) {
					sb_add(m, "INCOMPLETE [%u bytes] )",
					       skb->len - ptr);
					return;
				}

				/* Length: 16 "SPI=0xF1234567 )" */
				sb_add(m, "SPI=0x%x )", ntohl(eh->spi));

			}
			return;
		default:
			/* Max length: 20 "Unknown Ext Hdr 255" */
			sb_add(m, "Unknown Ext Hdr %u", currenthdr);
			return;
		}
		if (logflags & XT_LOG_IPOPT)
			sb_add(m, ") ");

		currenthdr = hp->nexthdr;
		ptr += hdrlen;
	}

	switch (currenthdr) {
	case IPPROTO_TCP:
		if (dump_tcp_header(m, skb, currenthdr, fragment, ptr,
		    logflags))
			return;
		break;
	case IPPROTO_UDP:
	case IPPROTO_UDPLITE:
		if (dump_udp_header(m, skb, currenthdr, fragment, ptr))
			return;
		break;
	case IPPROTO_ICMPV6: {
		struct icmp6hdr _icmp6h;
		const struct icmp6hdr *ic;

		/* Max length: 13 "PROTO=ICMPv6 " */
		sb_add(m, "PROTO=ICMPv6 ");

		if (fragment)
			break;

		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
		ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
		if (ic == NULL) {
			sb_add(m, "INCOMPLETE [%u bytes] ", skb->len - ptr);
			return;
		}

		/* Max length: 18 "TYPE=255 CODE=255 " */
		sb_add(m, "TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);

		switch (ic->icmp6_type) {
		case ICMPV6_ECHO_REQUEST:
		case ICMPV6_ECHO_REPLY:
			/* Max length: 19 "ID=65535 SEQ=65535 " */
			sb_add(m, "ID=%u SEQ=%u ",
				ntohs(ic->icmp6_identifier),
				ntohs(ic->icmp6_sequence));
			break;
		case ICMPV6_MGM_QUERY:
		case ICMPV6_MGM_REPORT:
		case ICMPV6_MGM_REDUCTION:
			break;

		case ICMPV6_PARAMPROB:
			/* Max length: 17 "POINTER=ffffffff " */
			sb_add(m, "POINTER=%08x ", ntohl(ic->icmp6_pointer));
			/* Fall through */
		case ICMPV6_DEST_UNREACH:
		case ICMPV6_PKT_TOOBIG:
		case ICMPV6_TIME_EXCEED:
			/* Max length: 3+maxlen */
			if (recurse) {
				sb_add(m, "[");
				dump_ipv6_packet(m, info, skb,
					    ptr + sizeof(_icmp6h), 0);
				sb_add(m, "] ");
			}

			/* Max length: 10 "MTU=65535 " */
			if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
				sb_add(m, "MTU=%u ", ntohl(ic->icmp6_mtu));
		}
		break;
	}
	/* Max length: 10 "PROTO=255 " */
	default:
		sb_add(m, "PROTO=%u ", currenthdr);
	}

	/* Max length: 15 "UID=4294967295 " */
	if ((logflags & XT_LOG_UID) && recurse)
		dump_sk_uid_gid(m, skb->sk);

	/* Max length: 16 "MARK=0xFFFFFFFF " */
	if (!recurse && skb->mark)
		sb_add(m, "MARK=0x%x ", skb->mark);
}
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 ahhdr *ah = NULL;
       const struct ip6t_ah *ahinfo = matchinfo;
       unsigned int temp;
       int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;

       /*DEBUGP("IPv6 AH entered\n");*/
       /* if (opt->auth == 0) return 0;
       * It does not filled on output */

       /* 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 (ip6t_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr *hdr;

              DEBUGP("ipv6_ah 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=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);

              /* AH -> evaluate */
                if (nexthdr == NEXTHDR_AUTH) {
                     temp |= MASK_AH;
                     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_ah match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_ah: new pointer too large! \n");
			break;
		}
        }

       /* AH header not found */
       if ( temp != MASK_AH ) return 0;

       if (len < (int)sizeof(struct ahhdr)){
	       *hotdrop = 1;
       		return 0;
       }

       ah=skb->data+ptr;

       DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
       DEBUGP("RES %04X ", ah->reserved);
       DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));

       DEBUGP("IPv6 AH spi %02X ",
       		(spi_match(ahinfo->spis[0], ahinfo->spis[1],
                           ntohl(ah->spi),
                           !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
       DEBUGP("len %02X %04X %02X ",
       		ahinfo->hdrlen, hdrlen,
       		(!ahinfo->hdrlen ||
                           (ahinfo->hdrlen == hdrlen) ^
                           !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
       DEBUGP("res %02X %04X %02X\n", 
       		ahinfo->hdrres, ah->reserved,
       		!(ahinfo->hdrres && ah->reserved));

       return (ah != NULL)
              &&
              (spi_match(ahinfo->spis[0], ahinfo->spis[1],
                           ntohl(ah->spi),
                           !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
              &&
              (!ahinfo->hdrlen ||
                           (ahinfo->hdrlen == hdrlen) ^
                           !!(ahinfo->invflags & IP6T_AH_INV_LEN))
              &&
              !(ahinfo->hdrres && ah->reserved);
}
Beispiel #20
0
static inline void
_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
{
	int onlyproto = 0;
	u16 offset = skb_network_header_len(skb);
	struct ipv6hdr *hdr = ipv6_hdr(skb);
	struct ipv6_opt_hdr *exthdr;
	const unsigned char *nh = skb_network_header(skb);
	u8 nexthdr = nh[IP6CB(skb)->nhoff];

	memset(fl, 0, sizeof(struct flowi));
	ipv6_addr_copy(&fl->fl6_dst, reverse ? &hdr->saddr : &hdr->daddr);
	ipv6_addr_copy(&fl->fl6_src, reverse ? &hdr->daddr : &hdr->saddr);

	while (nh + offset + 1 < skb->data ||
	       pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
		nh = skb_network_header(skb);
		exthdr = (struct ipv6_opt_hdr *)(nh + offset);

		switch (nexthdr) {
		case NEXTHDR_FRAGMENT:
			onlyproto = 1;
		case NEXTHDR_ROUTING:
		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr *)(nh + offset);
			break;

		case IPPROTO_UDP:
		case IPPROTO_UDPLITE:
		case IPPROTO_TCP:
		case IPPROTO_SCTP:
		case IPPROTO_DCCP:
			if (!onlyproto && (nh + offset + 4 < skb->data ||
			     pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
				__be16 *ports = (__be16 *)exthdr;

				fl->fl_ip_sport = ports[!!reverse];
				fl->fl_ip_dport = ports[!reverse];
			}
			fl->proto = nexthdr;
			return;

		case IPPROTO_ICMPV6:
			if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
				u8 *icmp = (u8 *)exthdr;

				fl->fl_icmp_type = icmp[0];
				fl->fl_icmp_code = icmp[1];
			}
			fl->proto = nexthdr;
			return;

#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
		case IPPROTO_MH:
			if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
				struct ip6_mh *mh;
				mh = (struct ip6_mh *)exthdr;

				fl->fl_mh_type = mh->ip6mh_type;
			}
			fl->proto = nexthdr;
			return;
#endif

		/* XXX Why are there these headers? */
		case IPPROTO_AH:
		case IPPROTO_ESP:
		case IPPROTO_COMP:
		default:
			fl->fl_ipsec_spi = 0;
			fl->proto = nexthdr;
			return;
		}
	}
}
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
	struct ipv6_rt_hdr _route, *rh;
	const struct ip6t_rt *rtinfo = matchinfo;
	unsigned int temp;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	unsigned int ret = 0;
	struct in6_addr *ap, _addr;
/* purpose     : Cisco CIAM Alert    author : Rain    date : 2011-07-06 */
/* description : Patch ip6t_rt.c 2.6.16.31  for Cisco CIAM Alert        */
	int err;

/* purpose     : Cisco CIAM Alert    author : Rain    date : 2011-07-06 */
/* description : Patch ip6t_rt.c 2.6.16.31  for Cisco CIAM Alert        */
	/*if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0)
		return 0;*/
	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
	if (err < 0) {
		if (err != -ENOENT)
			*hotdrop = 1;
		return 0;
	}

	rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
	if (rh == NULL) {
		*hotdrop = 1;
		return 0;
	}

	hdrlen = ipv6_optlen(rh);
	if (skb->len - ptr < hdrlen) {
		/* Pcket smaller than its length field */
		return 0;
	}

	DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
	DEBUGP("TYPE %04X ", rh->type);
	DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);

	DEBUGP("IPv6 RT segsleft %02X ",
	       (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			       rh->segments_left,
			       !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
	DEBUGP("type %02X %02X %02X ",
	       rtinfo->rt_type, rh->type,
	       (!(rtinfo->flags & IP6T_RT_TYP) ||
		((rtinfo->rt_type == rh->type) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
	DEBUGP("len %02X %04X %02X ",
	       rtinfo->hdrlen, hdrlen,
	       (!(rtinfo->flags & IP6T_RT_LEN) ||
		((rtinfo->hdrlen == hdrlen) ^
		 !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
	DEBUGP("res %02X %02X %02X ",
	       (rtinfo->flags & IP6T_RT_RES),
	       ((struct rt0_hdr *)rh)->reserved,
	       !((rtinfo->flags & IP6T_RT_RES) &&
		 (((struct rt0_hdr *)rh)->reserved)));

	ret = (rh != NULL)
	      &&
	      (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
			      rh->segments_left,
			      !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_LEN) ||
	       ((rtinfo->hdrlen == hdrlen) ^
		!!(rtinfo->invflags & IP6T_RT_INV_LEN)))
	      &&
	      (!(rtinfo->flags & IP6T_RT_TYP) ||
	       ((rtinfo->rt_type == rh->type) ^
		!!(rtinfo->invflags & IP6T_RT_INV_TYP)));

	if (ret && (rtinfo->flags & IP6T_RT_RES)) {
		u_int32_t *rp, _reserved;
		rp = skb_header_pointer(skb,
					ptr + offsetof(struct rt0_hdr,
						       reserved),
					sizeof(_reserved),
					&_reserved);

		ret = (*rp == 0);
	}
Beispiel #22
0
static int
match(const struct sk_buff *skb,
      const struct net_device *in,
      const struct net_device *out,
      const void *matchinfo,
      int offset,
      unsigned int protoff,
      int *hotdrop)
{
       struct ipv6_rt_hdr _route, *rh = NULL;
       const struct ip6t_rt *rtinfo = matchinfo;
       unsigned int temp;
       unsigned int len;
       u8 nexthdr;
       unsigned int ptr;
       unsigned int hdrlen = 0;
       unsigned int ret = 0;
       struct in6_addr *ap, _addr;

       /* 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 (ip6t_ext_hdr(nexthdr)) {
               struct ipv6_opt_hdr _hdr, *hp;

              DEBUGP("ipv6_rt 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;
              }

	      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 = (hp->hdrlen+2)<<2;
                else
                        hdrlen = ipv6_optlen(hp);

              /* ROUTING -> evaluate */
                if (nexthdr == NEXTHDR_ROUTING) {
                     temp |= MASK_ROUTING;
                     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_rt match: unknown nextheader %u\n",nexthdr);
                            return 0;
                            break;
              }

                nexthdr = hp->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_rt: new pointer is too large! \n");
			break;
		}
        }

       /* ROUTING header not found */
       if ( temp != MASK_ROUTING ) return 0;

       if (len < (int)sizeof(struct ipv6_rt_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

       if (len < hdrlen){
	       /* Pcket smaller than its length field */
       		return 0;
       }

       rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
       BUG_ON(rh == NULL);

       DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
       DEBUGP("TYPE %04X ", rh->type);
       DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);

       DEBUGP("IPv6 RT segsleft %02X ",
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           rh->segments_left,
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
       DEBUGP("type %02X %02X %02X ",
       		rtinfo->rt_type, rh->type, 
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == rh->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
       DEBUGP("len %02X %04X %02X ",
       		rtinfo->hdrlen, hdrlen,
       		(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
       DEBUGP("res %02X %02X %02X ", 
       		(rtinfo->flags & IP6T_RT_RES), ((struct rt0_hdr *)rh)->bitmap,
       		!((rtinfo->flags & IP6T_RT_RES) && (((struct rt0_hdr *)rh)->bitmap)));

       ret = (rh != NULL)
       		&&
       		(segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
                           rh->segments_left,
                           !!(rtinfo->invflags & IP6T_RT_INV_SGS)))
		&&
	      	(!(rtinfo->flags & IP6T_RT_LEN) ||
                           ((rtinfo->hdrlen == hdrlen) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_LEN)))
		&&
       		(!(rtinfo->flags & IP6T_RT_TYP) ||
                           ((rtinfo->rt_type == rh->type) ^
                           !!(rtinfo->invflags & IP6T_RT_INV_TYP)));

	if (ret && (rtinfo->flags & IP6T_RT_RES)) {
		u_int32_t *bp, _bitmap;
		bp = skb_header_pointer(skb,
					ptr + offsetof(struct rt0_hdr, bitmap),
					sizeof(_bitmap), &_bitmap);

		ret = (*bp == 0);
	}
Beispiel #23
0
static inline void
_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
{
	struct flowi6 *fl6 = &fl->u.ip6;
	int onlyproto = 0;
	const struct ipv6hdr *hdr = ipv6_hdr(skb);
	u16 offset = sizeof(*hdr);
	struct ipv6_opt_hdr *exthdr;
	const unsigned char *nh = skb_network_header(skb);
	u16 nhoff = IP6CB(skb)->nhoff;
	int oif = 0;
	u8 nexthdr;

	if (!nhoff)
		nhoff = offsetof(struct ipv6hdr, nexthdr);

	nexthdr = nh[nhoff];

	if (skb_dst(skb))
		oif = skb_dst(skb)->dev->ifindex;

	memset(fl6, 0, sizeof(struct flowi6));
	fl6->flowi6_mark = skb->mark;
	fl6->flowi6_oif = reverse ? skb->skb_iif : oif;

	fl6->daddr = reverse ? hdr->saddr : hdr->daddr;
	fl6->saddr = reverse ? hdr->daddr : hdr->saddr;

	while (nh + offset + 1 < skb->data ||
	       pskb_may_pull(skb, nh + offset + 1 - skb->data)) {
		nh = skb_network_header(skb);
		exthdr = (struct ipv6_opt_hdr *)(nh + offset);

		switch (nexthdr) {
		case NEXTHDR_FRAGMENT:
			onlyproto = 1;
		case NEXTHDR_ROUTING:
		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr *)(nh + offset);
			break;

		case IPPROTO_UDP:
		case IPPROTO_UDPLITE:
		case IPPROTO_TCP:
		case IPPROTO_SCTP:
		case IPPROTO_DCCP:
			if (!onlyproto && (nh + offset + 4 < skb->data ||
			     pskb_may_pull(skb, nh + offset + 4 - skb->data))) {
				__be16 *ports;

				nh = skb_network_header(skb);
				ports = (__be16 *)(nh + offset);
				fl6->fl6_sport = ports[!!reverse];
				fl6->fl6_dport = ports[!reverse];
			}
			fl6->flowi6_proto = nexthdr;
			return;

		case IPPROTO_ICMPV6:
			if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) {
				u8 *icmp;

				nh = skb_network_header(skb);
				icmp = (u8 *)(nh + offset);
				fl6->fl6_icmp_type = icmp[0];
				fl6->fl6_icmp_code = icmp[1];
			}
			fl6->flowi6_proto = nexthdr;
			return;

#if IS_ENABLED(CONFIG_IPV6_MIP6)
		case IPPROTO_MH:
			offset += ipv6_optlen(exthdr);
			if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
				struct ip6_mh *mh;

				nh = skb_network_header(skb);
				mh = (struct ip6_mh *)(nh + offset);
				fl6->fl6_mh_type = mh->ip6mh_type;
			}
			fl6->flowi6_proto = nexthdr;
			return;
#endif

		/* XXX Why are there these headers? */
		case IPPROTO_AH:
		case IPPROTO_ESP:
		case IPPROTO_COMP:
		default:
			fl6->fl6_ipsec_spi = 0;
			fl6->flowi6_proto = nexthdr;
			return;
		}
	}
}
Beispiel #24
0
static inline void
_decode_session6(struct sk_buff *skb, struct flowi *fl)
{
	u16 offset = skb->h.raw - skb->nh.raw;
	struct ipv6hdr *hdr = skb->nh.ipv6h;
	struct ipv6_opt_hdr *exthdr;
	u8 nexthdr = skb->nh.raw[IP6CB(skb)->nhoff];

	memset(fl, 0, sizeof(struct flowi));
	ipv6_addr_copy(&fl->fl6_dst, &hdr->daddr);
	ipv6_addr_copy(&fl->fl6_src, &hdr->saddr);

	while (pskb_may_pull(skb, skb->nh.raw + offset + 1 - skb->data)) {
		exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);

		switch (nexthdr) {
		case NEXTHDR_ROUTING:
		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			offset += ipv6_optlen(exthdr);
			nexthdr = exthdr->nexthdr;
			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
			break;

		case IPPROTO_UDP:
		case IPPROTO_UDPLITE:
		case IPPROTO_TCP:
		case IPPROTO_SCTP:
		case IPPROTO_DCCP:
			if (pskb_may_pull(skb, skb->nh.raw + offset + 4 - skb->data)) {
				__be16 *ports = (__be16 *)exthdr;

				fl->fl_ip_sport = ports[0];
				fl->fl_ip_dport = ports[1];
			}
			fl->proto = nexthdr;
			return;

		case IPPROTO_ICMPV6:
			if (pskb_may_pull(skb, skb->nh.raw + offset + 2 - skb->data)) {
				u8 *icmp = (u8 *)exthdr;

				fl->fl_icmp_type = icmp[0];
				fl->fl_icmp_code = icmp[1];
			}
			fl->proto = nexthdr;
			return;

#ifdef CONFIG_IPV6_MIP6
		case IPPROTO_MH:
			if (pskb_may_pull(skb, skb->nh.raw + offset + 3 - skb->data)) {
				struct ip6_mh *mh;
				mh = (struct ip6_mh *)exthdr;

				fl->fl_mh_type = mh->ip6mh_type;
			}
			fl->proto = nexthdr;
			return;
#endif

		/* XXX Why are there these headers? */
		case IPPROTO_AH:
		case IPPROTO_ESP:
		case IPPROTO_COMP:
		default:
			fl->fl_ipsec_spi = 0;
			fl->proto = nexthdr;
			return;
		};
	}
}
Beispiel #25
0
/* One level of recursion won't kill us */
static void dump_packet(const struct nf_loginfo *info,
			const struct sk_buff *skb, unsigned int ip6hoff,
			int recurse)
{
	u_int8_t currenthdr;
	int fragment;
	struct ipv6hdr _ip6h;
	const struct ipv6hdr *ih;
	unsigned int ptr;
	unsigned int hdrlen = 0;
	unsigned int logflags;

	if (info->type == NF_LOG_TYPE_LOG)
		logflags = info->u.log.logflags;
	else
		logflags = NF_LOG_MASK;

	ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
	if (ih == NULL) {
		printk("TRUNCATED");
		return;
	}

	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
	printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr);

	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
	printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
	       (ntohl(*(__be32 *)ih) & 0x0ff00000) >> 20,
	       ih->hop_limit,
	       (ntohl(*(__be32 *)ih) & 0x000fffff));

	fragment = 0;
	ptr = ip6hoff + sizeof(struct ipv6hdr);
	currenthdr = ih->nexthdr;
	while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
		struct ipv6_opt_hdr _hdr;
		const struct ipv6_opt_hdr *hp;

		hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
		if (hp == NULL) {
			printk("TRUNCATED");
			return;
		}

		/* Max length: 48 "OPT (...) " */
		if (logflags & IP6T_LOG_IPOPT)
			printk("OPT ( ");

		switch (currenthdr) {
		case IPPROTO_FRAGMENT: {
			struct frag_hdr _fhdr;
			const struct frag_hdr *fh;

			printk("FRAG:");
			fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
						&_fhdr);
			if (fh == NULL) {
				printk("TRUNCATED ");
				return;
			}

			/* Max length: 6 "65535 " */
			printk("%u ", ntohs(fh->frag_off) & 0xFFF8);

			/* Max length: 11 "INCOMPLETE " */
			if (fh->frag_off & htons(0x0001))
				printk("INCOMPLETE ");

			printk("ID:%08x ", ntohl(fh->identification));

			if (ntohs(fh->frag_off) & 0xFFF8)
				fragment = 1;

			hdrlen = 8;

			break;
		}
		case IPPROTO_DSTOPTS:
		case IPPROTO_ROUTING:
		case IPPROTO_HOPOPTS:
			if (fragment) {
				if (logflags & IP6T_LOG_IPOPT)
					printk(")");
				return;
			}
			hdrlen = ipv6_optlen(hp);
			break;
		/* Max Length */
		case IPPROTO_AH:
			if (logflags & IP6T_LOG_IPOPT) {
				struct ip_auth_hdr _ahdr;
				const struct ip_auth_hdr *ah;

				/* Max length: 3 "AH " */
				printk("AH ");

				if (fragment) {
					printk(")");
					return;
				}

				ah = skb_header_pointer(skb, ptr, sizeof(_ahdr),
							&_ahdr);
				if (ah == NULL) {
					/*
					 * Max length: 26 "INCOMPLETE [65535
					 *  bytes] )"
					 */
					printk("INCOMPLETE [%u bytes] )",
					       skb->len - ptr);
					return;
				}

				/* Length: 15 "SPI=0xF1234567 */
				printk("SPI=0x%x ", ntohl(ah->spi));

			}

			hdrlen = (hp->hdrlen+2)<<2;
			break;
		case IPPROTO_ESP:
			if (logflags & IP6T_LOG_IPOPT) {
				struct ip_esp_hdr _esph;
				const struct ip_esp_hdr *eh;

				/* Max length: 4 "ESP " */
				printk("ESP ");

				if (fragment) {
					printk(")");
					return;
				}

				/*
				 * Max length: 26 "INCOMPLETE [65535 bytes] )"
				 */
				eh = skb_header_pointer(skb, ptr, sizeof(_esph),
							&_esph);
				if (eh == NULL) {
					printk("INCOMPLETE [%u bytes] )",
					       skb->len - ptr);
					return;
				}

				/* Length: 16 "SPI=0xF1234567 )" */
				printk("SPI=0x%x )", ntohl(eh->spi) );

			}
			return;
		default:
			/* Max length: 20 "Unknown Ext Hdr 255" */
			printk("Unknown Ext Hdr %u", currenthdr);
			return;
		}
		if (logflags & IP6T_LOG_IPOPT)
			printk(") ");

		currenthdr = hp->nexthdr;
		ptr += hdrlen;
	}

	switch (currenthdr) {
	case IPPROTO_TCP: {
		struct tcphdr _tcph;
		const struct tcphdr *th;

		/* Max length: 10 "PROTO=TCP " */
		printk("PROTO=TCP ");

		if (fragment)
			break;

		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
		th = skb_header_pointer(skb, ptr, sizeof(_tcph), &_tcph);
		if (th == NULL) {
			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
			return;
		}

		/* Max length: 20 "SPT=65535 DPT=65535 " */
		printk("SPT=%u DPT=%u ",
		       ntohs(th->source), ntohs(th->dest));
		/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
		if (logflags & IP6T_LOG_TCPSEQ)
			printk("SEQ=%u ACK=%u ",
			       ntohl(th->seq), ntohl(th->ack_seq));
		/* Max length: 13 "WINDOW=65535 " */
		printk("WINDOW=%u ", ntohs(th->window));
		/* Max length: 9 "RES=0x3C " */
		printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
		/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
		if (th->cwr)
			printk("CWR ");
		if (th->ece)
			printk("ECE ");
		if (th->urg)
			printk("URG ");
		if (th->ack)
			printk("ACK ");
		if (th->psh)
			printk("PSH ");
		if (th->rst)
			printk("RST ");
		if (th->syn)
			printk("SYN ");
		if (th->fin)
			printk("FIN ");
		/* Max length: 11 "URGP=65535 " */
		printk("URGP=%u ", ntohs(th->urg_ptr));

		if ((logflags & IP6T_LOG_TCPOPT) &&
		    th->doff * 4 > sizeof(struct tcphdr)) {
			u_int8_t _opt[60 - sizeof(struct tcphdr)];
			const u_int8_t *op;
			unsigned int i;
			unsigned int optsize = th->doff * 4
					       - sizeof(struct tcphdr);

			op = skb_header_pointer(skb,
						ptr + sizeof(struct tcphdr),
						optsize, _opt);
			if (op == NULL) {
				printk("OPT (TRUNCATED)");
				return;
			}

			/* Max length: 127 "OPT (" 15*4*2chars ") " */
			printk("OPT (");
			for (i =0; i < optsize; i++)
				printk("%02X", op[i]);
			printk(") ");
		}
		break;
	}
	case IPPROTO_UDP:
	case IPPROTO_UDPLITE: {
		struct udphdr _udph;
		const struct udphdr *uh;

		if (currenthdr == IPPROTO_UDP)
			/* Max length: 10 "PROTO=UDP "     */
			printk("PROTO=UDP " );
		else	/* Max length: 14 "PROTO=UDPLITE " */
			printk("PROTO=UDPLITE ");

		if (fragment)
			break;

		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
		uh = skb_header_pointer(skb, ptr, sizeof(_udph), &_udph);
		if (uh == NULL) {
			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
			return;
		}

		/* Max length: 20 "SPT=65535 DPT=65535 " */
		printk("SPT=%u DPT=%u LEN=%u ",
		       ntohs(uh->source), ntohs(uh->dest),
		       ntohs(uh->len));
		break;
	}
	case IPPROTO_ICMPV6: {
		struct icmp6hdr _icmp6h;
		const struct icmp6hdr *ic;

		/* Max length: 13 "PROTO=ICMPv6 " */
		printk("PROTO=ICMPv6 ");

		if (fragment)
			break;

		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
		ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
		if (ic == NULL) {
			printk("INCOMPLETE [%u bytes] ", skb->len - ptr);
			return;
		}

		/* Max length: 18 "TYPE=255 CODE=255 " */
		printk("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);

		switch (ic->icmp6_type) {
		case ICMPV6_ECHO_REQUEST:
		case ICMPV6_ECHO_REPLY:
			/* Max length: 19 "ID=65535 SEQ=65535 " */
			printk("ID=%u SEQ=%u ",
				ntohs(ic->icmp6_identifier),
				ntohs(ic->icmp6_sequence));
			break;
		case ICMPV6_MGM_QUERY:
		case ICMPV6_MGM_REPORT:
		case ICMPV6_MGM_REDUCTION:
			break;

		case ICMPV6_PARAMPROB:
			/* Max length: 17 "POINTER=ffffffff " */
			printk("POINTER=%08x ", ntohl(ic->icmp6_pointer));
			/* Fall through */
		case ICMPV6_DEST_UNREACH:
		case ICMPV6_PKT_TOOBIG:
		case ICMPV6_TIME_EXCEED:
			/* Max length: 3+maxlen */
			if (recurse) {
				printk("[");
				dump_packet(info, skb, ptr + sizeof(_icmp6h),
					    0);
				printk("] ");
			}

			/* Max length: 10 "MTU=65535 " */
			if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
				printk("MTU=%u ", ntohl(ic->icmp6_mtu));
		}
		break;
	}
	/* Max length: 10 "PROTO=255 " */
	default:
		printk("PROTO=%u ", currenthdr);
	}

	/* Max length: 15 "UID=4294967295 " */
	if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) {
		read_lock_bh(&skb->sk->sk_callback_lock);
		if (skb->sk->sk_socket && skb->sk->sk_socket->file)
			printk("UID=%u GID=%u ",
				skb->sk->sk_socket->file->f_cred->fsuid,
				skb->sk->sk_socket->file->f_cred->fsgid);
		read_unlock_bh(&skb->sk->sk_callback_lock);
	}

	/* Max length: 16 "MARK=0xFFFFFFFF " */
	if (!recurse && skb->mark)
		printk("MARK=0x%x ", skb->mark);
}
Beispiel #26
0
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 ip_esp_hdr *esp = NULL;
	const struct ip6t_esp *espinfo = matchinfo;
	unsigned int temp;
	int len;
	u8 nexthdr;
	unsigned int ptr;

	/* Make sure this isn't an evil packet */
	/*DEBUGP("ipv6_esp entered \n");*/

	/* 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 (ip6t_ext_hdr(nexthdr)) {
        	struct ipv6_opt_hdr *hdr;
        	int hdrlen;

		DEBUGP("ipv6_esp 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) {
			temp |= MASK_ESP;
			break;
		}

		hdr=(struct ipv6_opt_hdr *)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);

		/* set the flag */
		switch (nexthdr){
			case NEXTHDR_HOP:
			case NEXTHDR_ROUTING:
			case NEXTHDR_FRAGMENT:
			case NEXTHDR_AUTH:
			case NEXTHDR_DEST:
				break;
			default:
				DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr);
				return 0;
				break;
		}

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if ( ptr > skb->len ) {
			DEBUGP("ipv6_esp: new pointer too large! \n");
			break;
		}
        }

	/* ESP header not found */
	if ( temp != MASK_ESP ) return 0;

       if (len < (int)sizeof(struct ip_esp_hdr)){
	       *hotdrop = 1;
       		return 0;
       }

	esp = (struct ip_esp_hdr *) (skb->data + ptr);

	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));

	return (esp != NULL)
		&& spi_match(espinfo->spis[0], espinfo->spis[1],
			      ntohl(esp->spi),
			      !!(espinfo->invflags & IP6T_ESP_INV_SPI));
}
Beispiel #27
0
static bool
ipv6header_mt6(const struct sk_buff *skb, const struct net_device *in,
               const struct net_device *out, const struct xt_match *match,
               const void *matchinfo, int offset, unsigned int protoff,
               bool *hotdrop)
{
	const struct ip6t_ipv6header_info *info = matchinfo;
	unsigned int temp;
	int len;
	u8 nexthdr;
	unsigned int ptr;

	/* Make sure this isn't an evil packet */

	/* type of the 1st exthdr */
	nexthdr = ipv6_hdr(skb)->nexthdr;
	/* pointer to the 1st exthdr */
	ptr = sizeof(struct ipv6hdr);
	/* available length */
	len = skb->len - ptr;
	temp = 0;

	while (ip6t_ext_hdr(nexthdr)) {
		struct ipv6_opt_hdr _hdr, *hp;
		int hdrlen;

		/* Is there enough space for the next ext header? */
		if (len < (int)sizeof(struct ipv6_opt_hdr))
			return false;
		/* No more exthdr -> evaluate */
		if (nexthdr == NEXTHDR_NONE) {
			temp |= MASK_NONE;
			break;
		}
		/* ESP -> evaluate */
		if (nexthdr == NEXTHDR_ESP) {
			temp |= MASK_ESP;
			break;
		}

		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 = (hp->hdrlen + 2) << 2;
		else
			hdrlen = ipv6_optlen(hp);

		/* set the flag */
		switch (nexthdr) {
		case NEXTHDR_HOP:
			temp |= MASK_HOPOPTS;
			break;
		case NEXTHDR_ROUTING:
			temp |= MASK_ROUTING;
			break;
		case NEXTHDR_FRAGMENT:
			temp |= MASK_FRAGMENT;
			break;
		case NEXTHDR_AUTH:
			temp |= MASK_AH;
			break;
		case NEXTHDR_DEST:
			temp |= MASK_DSTOPTS;
			break;
		default:
			return false;
			break;
		}

		nexthdr = hp->nexthdr;
		len -= hdrlen;
		ptr += hdrlen;
		if (ptr > skb->len)
			break;
	}

	if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP)
		temp |= MASK_PROTO;

	if (info->modeflag)
		return !((temp ^ info->matchflags ^ info->invflags)
			 & info->matchflags);
	else {
		if (info->invflags)
			return temp != info->matchflags;
		else
			return temp == info->matchflags;
	}
}
Beispiel #28
0
static int
ipv6header_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)
{
	const struct ip6t_ipv6header_info *info = matchinfo;
	unsigned int temp;
	int len;
	u8 nexthdr;
	unsigned int ptr;

	/* Make sure this isn't an evil packet */

	/* 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 (ip6t_ext_hdr(nexthdr)) {
        	struct ipv6_opt_hdr *hdr;
        	int hdrlen;

		/* 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) {
			temp |= MASK_NONE;
			break;
		}
		/* ESP -> evaluate */
                if (nexthdr == NEXTHDR_ESP) {
			temp |= MASK_ESP;
			break;
		}

		hdr=(struct ipv6_opt_hdr *)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);

		/* set the flag */
		switch (nexthdr){
			case NEXTHDR_HOP:
				temp |= MASK_HOPOPTS;
				break;
			case NEXTHDR_ROUTING:
				temp |= MASK_ROUTING;
				break;
			case NEXTHDR_FRAGMENT:
				temp |= MASK_FRAGMENT;
				break;
			case NEXTHDR_AUTH:
				temp |= MASK_AH;
				break;
			case NEXTHDR_DEST:
				temp |= MASK_DSTOPTS;
				break;
			default:
				return 0;
				break;
		}

                nexthdr = hdr->nexthdr;
                len -= hdrlen;
                ptr += hdrlen;
		if (ptr > skb->len)
			break;
        }

	if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
		temp |= MASK_PROTO;

	if (info->modeflag)
		return (!( (temp & info->matchflags)
			^ info->matchflags) ^ info->invflags);
	else
		return (!( temp ^ info->matchflags) ^ info->invflags);
}
Beispiel #29
0
static int tcf_csum_ipv6(struct sk_buff *skb, u32 update_flags)
{
	struct ipv6hdr *ip6h;
	struct ipv6_opt_hdr *ip6xh;
	unsigned int hl, ixhl;
	unsigned int pl;
	int ntkoff;
	u8 nexthdr;

	ntkoff = skb_network_offset(skb);

	hl = sizeof(*ip6h);

	if (!pskb_may_pull(skb, hl + ntkoff))
		goto fail;

	ip6h = ipv6_hdr(skb);

	pl = ntohs(ip6h->payload_len);
	nexthdr = ip6h->nexthdr;

	do {
		switch (nexthdr) {
		case NEXTHDR_FRAGMENT:
			goto ignore_skb;
		case NEXTHDR_ROUTING:
		case NEXTHDR_HOP:
		case NEXTHDR_DEST:
			if (!pskb_may_pull(skb, hl + sizeof(*ip6xh) + ntkoff))
				goto fail;
			ip6xh = (void *)(skb_network_header(skb) + hl);
			ixhl = ipv6_optlen(ip6xh);
			if (!pskb_may_pull(skb, hl + ixhl + ntkoff))
				goto fail;
			if ((nexthdr == NEXTHDR_HOP) &&
			    !(tcf_csum_ipv6_hopopts(ip6xh, ixhl, &pl)))
				goto fail;
			nexthdr = ip6xh->nexthdr;
			hl += ixhl;
			break;
		case IPPROTO_ICMPV6:
			if (update_flags & TCA_CSUM_UPDATE_FLAG_ICMP)
				if (!tcf_csum_ipv6_icmp(skb, ip6h,
							hl, pl + sizeof(*ip6h)))
					goto fail;
			goto done;
		case IPPROTO_TCP:
			if (update_flags & TCA_CSUM_UPDATE_FLAG_TCP)
				if (!tcf_csum_ipv6_tcp(skb, ip6h,
						       hl, pl + sizeof(*ip6h)))
					goto fail;
			goto done;
		case IPPROTO_UDP:
			if (update_flags & TCA_CSUM_UPDATE_FLAG_UDP)
				if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
						       pl + sizeof(*ip6h), 0))
					goto fail;
			goto done;
		case IPPROTO_UDPLITE:
			if (update_flags & TCA_CSUM_UPDATE_FLAG_UDPLITE)
				if (!tcf_csum_ipv6_udp(skb, ip6h, hl,
						       pl + sizeof(*ip6h), 1))
					goto fail;
			goto done;
		default:
			goto ignore_skb;
		}
	} while (pskb_may_pull(skb, hl + 1 + ntkoff));

done:
ignore_skb:
	return 1;

fail:
	return 0;
}
Beispiel #30
0
/**
 * Walks through @skb's headers, collecting data and adding it to @meta.
 *
 * @hdr6_offset number of bytes between skb->data and the IPv6 header.
 *
 * BTW: You might want to read summarize_skb4() first, since it's a lot simpler.
 */
static verdict summarize_skb6(struct xlation *state,
		unsigned int hdr6_offset,
		struct pkt_metadata *meta)
{
	union {
		struct ipv6_opt_hdr opt;
		struct frag_hdr frag;
		struct tcphdr tcp;
	} buffer;
	union {
		struct ipv6_opt_hdr *opt;
		struct frag_hdr *frag;
		struct tcphdr *tcp;
		u8 *nexthdr;
	} ptr;

	struct sk_buff *skb = state->in.skb;
	u8 nexthdr;
	unsigned int offset;
	bool is_first = true;

	ptr.nexthdr = skb_hdr_ptr(skb,
			hdr6_offset + offsetof(struct ipv6hdr, nexthdr),
			nexthdr);
	if (!ptr.nexthdr)
		return truncated(state, "IPv6 header");
	nexthdr = *ptr.nexthdr;
	offset = hdr6_offset + sizeof(struct ipv6hdr);

	meta->has_frag_hdr = false;

	do {
		switch (nexthdr) {
		case NEXTHDR_TCP:
			meta->l4_proto = L4PROTO_TCP;
			meta->l4_offset = offset;
			meta->payload_offset = offset;

			if (is_first) {
				ptr.tcp = skb_hdr_ptr(skb, offset, buffer.tcp);
				if (!ptr.tcp)
					return truncated(state, "TCP header");
				meta->payload_offset += tcp_hdr_len(ptr.tcp);
			}

			return VERDICT_CONTINUE;

		case NEXTHDR_UDP:
			meta->l4_proto = L4PROTO_UDP;
			meta->l4_offset = offset;
			meta->payload_offset = is_first
					? (offset + sizeof(struct udphdr))
					: offset;
			return VERDICT_CONTINUE;

		case NEXTHDR_ICMP:
			meta->l4_proto = L4PROTO_ICMP;
			meta->l4_offset = offset;
			meta->payload_offset = is_first
					? (offset + sizeof(struct icmp6hdr))
					: offset;
			return VERDICT_CONTINUE;

		case NEXTHDR_FRAGMENT:
			ptr.frag = skb_hdr_ptr(skb, offset, buffer.frag);
			if (!ptr.frag)
				return truncated(state, "fragment header");

			meta->has_frag_hdr = true;
			meta->frag_offset = offset;
			is_first = is_first_frag6(ptr.frag);

			offset += sizeof(struct frag_hdr);
			nexthdr = ptr.frag->nexthdr;
			break;

		case NEXTHDR_HOP:
		case NEXTHDR_ROUTING:
		case NEXTHDR_DEST:
			ptr.opt = skb_hdr_ptr(skb, offset, buffer.opt);
			if (!ptr.opt)
				return truncated(state, "extension header");

			offset += ipv6_optlen(ptr.opt);
			nexthdr = ptr.opt->nexthdr;
			break;

		default:
			meta->l4_proto = L4PROTO_OTHER;
			meta->l4_offset = offset;
			meta->payload_offset = offset;
			return VERDICT_CONTINUE;
		}
	} while (true);

	return VERDICT_CONTINUE; /* whatever. */
}