Defragging/refragging IPv6 packets

From: Brad Chapman (kakadu@earthlink.net)
Date: Thu May 31 2001 - 15:21:52 EST


Hello,

   My name is Brad Chapman and I am currently attempting to port the
iptables ip_conntrack component of Netfilter to the IPv6 protocol. My
port is almost feature-complete, but I cannot figure out how to properly
defragment/refragment IPv6 packets. Also, I have written an IPv6 header
parsing function to grab headers from the IPv6 header chain. I would
appreciate some feedback on that as well. Below are some code examples.

DEFRAGGING PACKETS:

/* Returns defragged sk_buff, or NULL */
/* FIXME: is this the "right" way to do it? -- BC */
struct sk_buff *ip6_ct_gather_frags(struct sk_buff *skb)
{
#ifdef CONFIG_NETFILTER_DEBUG
        unsigned int old_debug = skb->nf_debug;
#endif
        struct frag_hdr *fhdr = (struct frag_hdr *)
                                ipv6_get_header(skb->nh.ipv6h,
                                                NEXTHDR_FRAGMENT,
                                                NULL);
        local_bh_disable();
        if (!ipv6_reassembly(skb, (u8 *)fhdr))
                return NULL;
        local_bh_enable();

        skb->nfcache |= NFC_ALTERED;
#ifdef CONFIG_NETFILTER_DEBUG
        skb->nf_debug = old_debug;
#endif
        return skb;
}

REFRAGGING PACKETS:

/* This gets the fragmentable part - I think -- BC */
static int ip6_refrag_getfrag(const void *data, struct in6_addr *addr,
                              char *buff, unsigned int offset, unsigned int len)
{
        return 0;
}

static unsigned int ip6_refrag(unsigned int hooknum,
                              struct sk_buff **pskb,
                              const struct net_device *in,
                              const struct net_device *out,
                              int (*okfn)(struct sk_buff *))
{
        struct frag_hdr *fhdr = (struct frag_hdr *)
                                ipv6_get_header((*pskb)->nh.ipv6h,
                                                NEXTHDR_FRAGMENT,
                                                NULL);
        struct flowi *flow;
        int ret;
        __u8 protonum;

        /* Verify the protocol */
        if (!ipv6_get_header((*pskb)->nh.ipv6h, NEXTHDR_PROTOANY, &protonum))
                return NF_DROP;

        /* We've seen it coming out the other side: confirm */
        ip6_confirm(hooknum, pskb, in, out, okfn);

        /* Local packets are never produced too large for their
           interface. We degfragment them at LOCAL_OUT, however,
           so we have to refragment them here. */
        if ((fhdr) && !(fhdr->frag_off & htons(IP6_NON_FRAG_OFFSET))) {

                /* Build the flowlabel */
                flow.proto = (int)protonum;
                ipv6_addr_copy(flow.fl6_src, (*pskb)->nh.ipv6h->saddr);
                ipv6_addr_copy(flow.fl6_dst, (*pskb)->nh.ipv6h->daddr);
                flow.fl6_flowlabel = 0;
                
                if (protonum == NEXTHDR_TCP) {
                        flow.uli_u.ports.sport = (*pskb)->nh.tcph->sport;
                        flow.uli_u.ports.dport = (*pskb)->nh.tcph->dport;
                }
                else if (protonum == NEXTHDR_UDP) {
                        flow.uli_u.ports.sport = (*pskb)->nh.udph->sport;
                        flow.uli_u.ports.dport = (*pskb)->nh.udph->dport;
                }
                else if (protonum == NEXTHDR_ICMP) {
                        struct icmp6hdr *icmph;
                        icmph = (struct icmp6hdr *)ipv6_get_header((*pskb)->nh.ipv6h,
                                                                   NEXTHDR_ICMP,
                                                                   NULL);
                        if (!icmph)
                                return NF_DROP;
                        
                        flow.uli_u.icmpt.type = icmph->icmp6_type;
                        flow.uli_u.icmpt.code = icmph->icmp6_code;
                }
                else
                        return NF_DROP;
                
                ret = ip6_build_xmit((*pskb)->sk,
                                     ip6_refrag_getfrag,
                                     (*pskb)->data,
                                     flow,
                                     (*pskb)->nh.ipv6h->payload_len,
                                     NULL, 0, 0);

                if (ret < 0)
                        return NF_DROP;
                return NF_STOLEN;
        }
        return NF_ACCEPT;
}

PARSING IPV6 HEADERS

/* Find a particular header in the IPv6 header chains */
struct ipv6_opt_hdr *
ipv6_get_header(const struct ipv6hdr *ipv6h,
                __u8 header,
                __u8 *result)
{
        struct ipv6_opt_hdr *newhdr = NULL;
        __u8 *hdrptr = (__u8 *)&ipv6h->nexthdr;
        int hdrlen, length;

        IP_NF_ASSERT(header != NEXTHDR_NONE);
        IP_NF_ASSERT(*hdrptr != NEXTHDR_NONE);

        /* Start bouncing */
        length = sizeof(struct ipv6hdr);
        hdrlen = 0;
        while (*hdrptr != NEXTHDR_NONE)
        {
                if (header == NEXTHDR_PROTOANY &&
                    (*hdrptr == NEXTHDR_TCP ||
                     *hdrptr == NEXTHDR_UDP ||
                     *hdrptr == NEXTHDR_ICMP) &&
                    result != NULL)
                {
                        *result = *hdrptr;
                        newhdr = (struct ipv6_opt_hdr *)hdrptr;
                        break;
                } else if (*hdrptr == header) {
                        newhdr = (struct ipv6_opt_hdr *)hdrptr;
                        break;
                } else if (hdrlen > length) {
                        break;
                }
                hdrlen = sizeof((__u8 *)hdrptr);
                hdrptr = (__u8 *)(hdrptr + hdrlen);
                length -= hdrlen;
        }
        return newhdr;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu May 31 2001 - 21:00:53 EST