示例#1
0
struct dns_packet *
get_next_packet(struct dns_packet *decoded, pcap_parser_file * input)
{
    /* Misc. variables */
    char            fqdn[MAX_NAME + 1];
    unsigned int    fqdn_length;

    /* pcap-related variables */
    const uint8_t  *packet;     /* The actual packet */
    struct pcap_pkthdr header;  /* The header that pcap gives us */
    const struct sniff_ethernet *ethernet;      /* The ethernet header */
    unsigned short ethertype;
    const struct sniff_ipv4 *ipv4;      /* The IP header */
    const struct sniff_ipv6 *ipv6;
    const struct sniff_udp *udp;        /* The UDP header */
    const struct sniff_dns *dns;
    u_int           size_ip;
    u_int           size_layer2;
    unsigned short  ip_version;
    uint32_t        family;
    const uint8_t  *qsection;
    uint8_t         labelsize;
    uint16_t        add_type;
    uint16_t        edns_size;
    uint16_t        extended_rcode_and_version;
    uint16_t        zpart;
    const uint8_t  *sectionptr;
    const uint8_t  *where_am_i; /* Cursor in packet */
    bool            end_of_name;
    unsigned int    size_header;
    bool            end_of_headers, fragmented;
    uint8_t         next_v6_header;
    const struct sniff_eh *eh;  /* The IPv6 extension header, if present */
    const struct sniff_frag *frag;

    assert(decoded->qname != NULL);
    /* Grab next packet */
    decoded->rank = input->packetnum;
  next_packet:
    packet = (uint8_t *) pcap_next(input->handle, &header);
    if (packet == NULL) {       /* End of file */
        return NULL;
    }
    input->packetnum++;
    decoded->length = header.len;
    decoded->captured_length = header.caplen;
    decoded->date = header.ts;
    if (input->firstpacket.tv_sec == 0 && input->firstpacket.tv_usec == 0) {
        input->firstpacket = header.ts;
    }
    input->lastpacket = header.ts;
    if (input->datalink == DLT_EN10MB) {
        size_layer2 = SIZE_ETHERNET;
        ethernet = (struct sniff_ethernet *) (packet);
	ethertype = ntohs(ethernet->ether_type);
	if (ethertype == VLAN_ETHERTYPE) {
	    packet += 4;
	    ethernet = (struct sniff_ethernet *) (packet);
	    ethertype = ntohs(ethernet->ether_type);
	}
        if (ethertype == IPv6_ETHERTYPE) {
            ip_version = 6;
        } else if (ethertype == IPv4_ETHERTYPE) {
            ip_version = 4;
        } else {                /* Ignore other Ethernet types */
            goto next_packet;
        }
    } else if (input->datalink == DLT_LOOP) {
        size_layer2 = SIZE_LOOP;
        family = (ntohl(*((uint32_t *) packet)));
        if (family == PF_INET6) {
            ip_version = 6;
        } else if (family == PF_INET) {
            ip_version = 4;
        } else {                /* Ignore other packet types */
            goto next_packet;
        }
    } else {
        fatal("Unsupported data link type %s (%i)\n",
              pcap_datalink_val_to_description(input->datalink), input->datalink);
    }
    if (ip_version == 6) {
        ipv6 = (struct sniff_ipv6 *) (packet + size_layer2);
        size_ip = SIZE_IPv6;
        assert(IPV6_VERSION(ipv6) == 6);
        next_v6_header = ipv6->ip_nxt;
        size_header = 0;
        where_am_i = where_am_i + SIZE_IPv6;
        end_of_headers = false;
        fragmented = false;
        while (!end_of_headers) {
            /* Extension headers defined in RFC 2460, section 4 */
            if (next_v6_header == 0 ||
                next_v6_header == 43 || next_v6_header == 50
                || next_v6_header == 51 || next_v6_header == 60) {
                eh = (struct sniff_eh *) (where_am_i);
                next_v6_header = eh->eh_next;
                size_header = eh->eh_length;
            }
            /* Fragment */
            else if (next_v6_header == 44) {
                fragmented = 1;
                frag = (struct sniff_frag *) (where_am_i);
                next_v6_header = frag->frag_next;
                size_header = SIZE_FRAGMENT_HDR;
            } else {
                end_of_headers = true;
            }
            where_am_i = where_am_i + size_header;
            size_ip += size_header;
            if ((size_layer2 + size_ip) > decoded->captured_length) {
                if (verbose) {
                    fprintf(stdout,
                            "Warning: ignoring packet #%li because IPv6 headers too large\n",
                            input->packetnum);
                }
                goto next_packet;
            }
        }
        if (fragmented && FRAG_OFFSET(frag) == 0) {
            goto next_packet;
        }
    } else if (ip_version == 4) {
        ipv4 = (struct sniff_ipv4 *) (packet + size_layer2);
        size_ip = IP_HL(ipv4) * 4;
        assert(IPV4_VERSION(ipv4) == 4);
    } else {
        /* Should never happen */
        assert(0);
    }
    if ((ip_version == 6 && next_v6_header == UDP)
        || (ip_version == 4 && ipv4->ip_p == UDP)) {
        if (ip_version == 6) {
            assert(decoded->src != NULL);
            assert(decoded->dst != NULL);
            inet_ntop(AF_INET6, &ipv6->ip_src, decoded->src, INET6_ADDRSTRLEN);
            inet_ntop(AF_INET6, &ipv6->ip_dst, decoded->dst, INET6_ADDRSTRLEN);
        } else if (ip_version == 4) {
            assert(decoded->src != NULL);
            assert(decoded->dst != NULL);
            inet_ntop(AF_INET, &ipv4->ip_src, decoded->src, INET_ADDRSTRLEN);
            inet_ntop(AF_INET, &ipv4->ip_dst, decoded->dst, INET_ADDRSTRLEN);
        } else {
            goto next_packet;
        }
        udp = (struct sniff_udp *) (packet + size_layer2 + size_ip);
        decoded->src_port = (u_short) ntohs(udp->sport);
        decoded->dst_port = (u_short) ntohs(udp->dport);
        if (decoded->src_port == DNS_PORT || decoded->dst_port == DNS_PORT) {
            if (maxpackets > 0 && input->dnspacketnum >= maxpackets) {
                return NULL;
            }
            dns = (struct sniff_dns *) (packet + size_layer2 + size_ip + SIZE_UDP);
            decoded->query = DNS_QR(dns) == 0 ? true : false;
            decoded->query_id = dns->query_id;
            decoded->opcode = DNS_OPCODE(dns);
            decoded->returncode = DNS_RCODE(dns);
            decoded->aa = DNS_AA(dns) ? true : false;
            decoded->tc = DNS_TC(dns) ? true : false;
            decoded->rd = DNS_RD(dns) ? true : false;
            decoded->ra = DNS_RA(dns) ? true : false;
            decoded->ancount = ntohs(dns->ancount);
            decoded->nscount = ntohs(dns->nscount);
            decoded->arcount = ntohs(dns->arcount);
            qsection = (uint8_t *) (packet +
                                    size_layer2 + size_ip + SIZE_UDP + SIZE_DNS);
            fqdn[0] = '\0';
            end_of_name = false;
            for (sectionptr = qsection; !end_of_name;) {
                CHECK_SECTIONPTR(1);
                labelsize = (uint8_t) * sectionptr;
                if (labelsize == 0) {
                    sectionptr++;
                    end_of_name = true;
                } else if (labelsize > 63) {
                    /* It can be an error/attack or it can be compression (RFC 1035, 
                     * section 4.1.4). Today, we ignore packets with compression (we 
                     * just parse the question section, anyway). * * * * * * * *
                     * TODO */
                    if (verbose) {
                        fprintf(stdout,
                                "Warning: ignoring packet #%li because labelsize > 63\n",
                                input->packetnum);
                    }
                    goto next_packet;
                } else {
                    CHECK_SECTIONPTR(labelsize);
                    if (strlen(fqdn) == 0) {
                        strncpy(fqdn, (char *)
                                sectionptr + 1, labelsize);
                        fqdn_length = labelsize;
                    } else {
                        fqdn_length = strlen(fqdn);
                        if (fqdn_length + labelsize > MAX_NAME) {
                            if (verbose) {
                                fprintf(stdout,
                                        "Warning: ignoring packet #%li because malformed (FQDN length is already %i and label size is %i bytes)\n",
                                        input->packetnum, fqdn_length, labelsize);
                            };
                            goto next_packet;
                        }
                        strncat(fqdn, ".", 1);
                        strncat(fqdn, (char *)
                                sectionptr + 1, labelsize);
                        fqdn_length += (labelsize + 1);
                    }
                    if (fqdn_length > MAX_NAME) {
                        if (verbose) {
                            fprintf(stdout,
                                    "Warning: ignoring packet #%li because FQDN length > %i\n",
                                    input->packetnum, MAX_NAME);
                        }
                        goto next_packet;
                    }
                    fqdn[fqdn_length] = '\0';
                    sectionptr = sectionptr + labelsize + 1;
                    CHECK_SECTIONPTR(0);
                }
            }
            CHECK_SECTIONPTR(2);
            strcpy(decoded->qname, fqdn);
#ifdef PICKY_WITH_ALIGNMENT
            decoded->qtype = unaligned_uint16(sectionptr);
#else
            decoded->qtype = ntohs(*((uint16_t *) sectionptr));
#endif
            sectionptr += 2;
            CHECK_SECTIONPTR(2);
#ifdef PICKY_WITH_ALIGNMENT
            decoded->qclass = unaligned_uint16(sectionptr);
#else
            decoded->qclass = ntohs(*((uint16_t *) sectionptr));
#endif
            sectionptr += 2;
            decoded->edns0 = false;
            if (decoded->query) {
                edns_size = 0;
                if (dns->ancount == 0 && dns->nscount == 0) {
                    /* Probably by far the most common case in queries... */
                    if (dns->arcount != 0) {    /* There is an additional section.
                                                 * Probably the OPT * * * * * * * *
                                                 * * * * * of EDNS */
                        CHECK_SECTIONPTR(1);
                        labelsize = (uint8_t) * sectionptr;
                        if (labelsize == 0) {   /* Yes, EDNS0 */
                            sectionptr += 1;
                            CHECK_SECTIONPTR(2);
#ifdef PICKY_WITH_ALIGNMENT
                            add_type = unaligned_uint16(sectionptr);
#else
                            add_type = ntohs(*((uint16_t *) sectionptr));
#endif
                            sectionptr += 2;
                            CHECK_SECTIONPTR(2);
                            if (add_type == OPT) {
#ifdef PICKY_WITH_ALIGNMENT
                                edns_size = unaligned_uint16(sectionptr);
#else
                                edns_size = ntohs(*((uint16_t *) sectionptr));
#endif
                                decoded->edns0 = true;
                                /* RFC 2671 */
                                sectionptr += 2;
                                CHECK_SECTIONPTR(2);
#ifdef PICKY_WITH_ALIGNMENT
                                extended_rcode_and_version =
                                    unaligned_uint16(sectionptr);
#else
                                extended_rcode_and_version =
                                    ntohs(*((uint16_t *) sectionptr));
#endif
                                sectionptr += 2;
                                CHECK_SECTIONPTR(2);
#ifdef PICKY_WITH_ALIGNMENT
                                zpart = unaligned_uint16(sectionptr);
#else
                                zpart = ntohs(*((uint16_t *) sectionptr));
#endif
                                /* RFC 3225 */
                                decoded->do_dnssec =
                                    DNS_DO_DNSSEC(zpart) ? true : false;
                            }
                            sectionptr += 2;
			    /* TODO: dissect the RDATA to find things
			       like the option code (such as 3 for
			       NSID)
			       http://www.iana.org/assignments/dns-parameters */
                        }
                    }
                }
            }
            if (decoded->edns0) {
                decoded->edns0_size = (unsigned int) edns_size;
            }
            input->dnspacketnum++;
            return decoded;
        }
    }
    goto next_packet;
}
示例#2
0
struct rte_mbuf *
rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl *tbl,
		struct rte_ip_frag_death_row *dr, struct rte_mbuf *mb, uint64_t tms,
		struct ipv6_hdr *ip_hdr, struct ipv6_extension_fragment *frag_hdr)
{
	struct ip_frag_pkt *fp;
	struct ip_frag_key key;
	uint16_t ip_len, ip_ofs;

	rte_memcpy(&key.src_dst[0], ip_hdr->src_addr, 16);
	rte_memcpy(&key.src_dst[2], ip_hdr->dst_addr, 16);

	key.id = frag_hdr->id;
	key.key_len = IPV6_KEYLEN;

	ip_ofs = FRAG_OFFSET(frag_hdr->frag_data) * 8;

	/*
	 * as per RFC2460, payload length contains all extension headers as well.
	 * since we don't support anything but frag headers, this is what we remove
	 * from the payload len.
	 */
	ip_len = rte_be_to_cpu_16(ip_hdr->payload_len) - sizeof(*frag_hdr);

	IP_FRAG_LOG(DEBUG, "%s:%d:\n"
		"mbuf: %p, tms: %" PRIu64
		", key: <" IPv6_KEY_BYTES_FMT ", %#x>, ofs: %u, len: %u, flags: %#x\n"
		"tbl: %p, max_cycles: %" PRIu64 ", entry_mask: %#x, "
		"max_entries: %u, use_entries: %u\n\n",
		__func__, __LINE__,
		mb, tms, IPv6_KEY_BYTES(key.src_dst), key.id, ip_ofs, ip_len, frag_hdr->more_frags,
		tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries,
		tbl->use_entries);

	/* try to find/add entry into the fragment's table. */
	fp = ip_frag_find(tbl, dr, &key, tms);
	if (fp == NULL) {
		IP_FRAG_MBUF2DR(dr, mb);
		return NULL;
	}

	IP_FRAG_LOG(DEBUG, "%s:%d:\n"
		"tbl: %p, max_entries: %u, use_entries: %u\n"
		"ipv6_frag_pkt: %p, key: <" IPv6_KEY_BYTES_FMT ", %#x>, start: %" PRIu64
		", total_size: %u, frag_size: %u, last_idx: %u\n\n",
		__func__, __LINE__,
		tbl, tbl->max_entries, tbl->use_entries,
		fp, IPv6_KEY_BYTES(fp->key.src_dst), fp->key.id, fp->start,
		fp->total_size, fp->frag_size, fp->last_idx);


	/* process the fragmented packet. */
	mb = ip_frag_process(fp, dr, mb, ip_ofs, ip_len,
			MORE_FRAGS(frag_hdr->frag_data));
	ip_frag_inuse(tbl, fp);

	IP_FRAG_LOG(DEBUG, "%s:%d:\n"
		"mbuf: %p\n"
		"tbl: %p, max_entries: %u, use_entries: %u\n"
		"ipv6_frag_pkt: %p, key: <" IPv6_KEY_BYTES_FMT ", %#x>, start: %" PRIu64
		", total_size: %u, frag_size: %u, last_idx: %u\n\n",
		__func__, __LINE__, mb,
		tbl, tbl->max_entries, tbl->use_entries,
		fp, IPv6_KEY_BYTES(fp->key.src_dst), fp->key.id, fp->start,
		fp->total_size, fp->frag_size, fp->last_idx);

	return mb;
}
示例#3
0
文件: sip_ip.c 项目: wdj729115299/sip
#include "sip.h"

inline int IP_IS_BROADCAST(struct net_device *dev, __be32 ip)
{
	int retval = 1;
	
	if((ip == IP_ADDR_ANY_VALUE) 						/*IP地址为本地任意IP地址*/
		||(~ip == IP_ADDR_ANY_VALUE))				/*或者为按位取反IP地址*/
	{
		DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n");
		retval = 1;									/*是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else if(ip == dev->ip_host.s_addr)	{				/*IP地址为本地地址*/
		DBGPRINT(DBG_LEVEL_NOTES, "IP is local ip\n");
		retval = 0;									/*不是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else if(((ip&dev->ip_netmask.s_addr) 				/*IP地址为本子网内地址*/
					== (dev->ip_host.s_addr &dev->ip_netmask.s_addr))
		&& ((ip & ~dev->ip_netmask.s_addr) 			/*与广播地址同网段*/
					==(IP_ADDR_BROADCAST_VALUE & ~dev->ip_netmask.s_addr))){
		DBGPRINT(DBG_LEVEL_NOTES, "IP is ANY ip\n");
		retval =1;									/*是广播地址*/
		goto EXITin_addr_isbroadcast;					/*退出*/
	}else{											/*不是广播IP地址*/
		retval = 0;
	}
EXITin_addr_isbroadcast:
	return retval;
}

#define IP_FREE_REASS(ipr)				\
do{										\
	struct skbuff *skb=NULL,*skb_prev=NULL;	\
	for(skb_prev = skb = ipr->skb; 			\
		skb != NULL; 						\
		skb_prev = skb, 					\
		skb = skb->next,					\
		skb_free(skb_prev));				\
		free(ipr);						\
}while(0);


#define IPREASS_TIMEOUT 3							/*IP分组重组的超时时间为3秒*/
static struct sip_reass *ip_reass_list = NULL;				/*IP重组的链表*/
struct skbuff *sip_reassemble(struct skbuff* skb)
{
	struct sip_iphdr *fraghdr = skb->nh.iph;
	int retval = 0;
	__u16 offset, len;
	int found = 0;

	offset = (fraghdr->frag_off & 0x1FFF)<<3;				/*取得IP分组偏移地址,32位长*/
	len = fraghdr->tot_len - fraghdr->ihl<<2;				/*IP分组的数据长度*/

	struct sip_reass *ipr = NULL,*ipr_prev = NULL;	
	for(ipr_prev = ipr= ip_reass_list; ipr != NULL;	)	
	{
		if(time(NULL) -ipr->timer > IPREASS_TIMEOUT)	/*此分组是超时?*/
		{
			if(ipr_prev == NULL)						/*第一个分片?*/
			{
				ipr_prev = ipr;						/*更新守护的指针为本分组*/
				ip_reass_list->next = ipr = ipr->next;	/*将超时的分片从重组链表上取下来*/
				ipr = ipr->next;						/*更新当前的分组指针*/
				IP_FREE_REASS(ipr_prev);				/*释放资源*/
				ipr_prev->next =NULL;					/*重置指针为空*/

				continue;							/*继续查找合适的分组*/
			}
			else										/*不是第一个分组*/
			{
				ipr_prev->next = ipr->next;				/*从分片链表上摘除当前链*/
				IP_FREE_REASS(ipr);					/*释放当前重组链*/
				ipr = ipr_prev->next;					/*更新当前链的指针*/
				continue;							/*继续查找*/
			}			
		}

		/*分片是否输入此条链*/
		if(ipr->iphdr.daddr == fraghdr->daddr 			/*目的IP地址匹配*/
			&&ipr->iphdr.saddr == fraghdr->saddr		/*源IP地址匹配*/
			&&ipr->iphdr.id == fraghdr->id)				/*分片的ID匹配*/
		{
			found = 1;								/*属于这条链*/
			break;
		}
	}

	if(!found)										/*没有找到合适的分组链?*/
	{
		ipr_prev = NULL;								/*初始化为空*/
		ipr = (struct sip_reass*)malloc(sizeof(struct sip_reass));/*申请一个分组数据结构*/
		if(!ipr)										/*申请失败*/
		{
			retval = -1;								/*返回值-1*/
			goto freeskb;							/*退出*/
		}

		memset(ipr, 0, sizeof(struct sip_reass));			/*初始化分组结构*/

		ipr->next = ip_reass_list;						/*将当前分组结构挂接到分组链的头部*/
		ip_reass_list = ipr;	

		memcpy(&ipr->iphdr, skb->nh.raw, sizeof(IPHDR_LEN));/*拷贝IP的数据头部,便于之后的分片匹配*/
	}else{											/*找到合适的分组链*/
		if(((fraghdr->frag_off & 0x1FFF) == 0)			/*当前数据位于分片第一个*/
			&&((ipr->iphdr.frag_off & 0x1FFF) != 0))		/*分组链上的头部不是第一个分片*/
		{
			memcpy(&ipr->iphdr, fraghdr, IPHDR_LEN);	/*更新重组中的IP头部结构*/
		}		
	}

	/* 检查是否为最后一个分组*/
	if( (fraghdr->frag_off & htons(0x2000)) == 0) {		/*没有更多分组*/
		#define IP_REASS_FLAG_LASTFRAG 0x01		

	  	ipr->flags |= IP_REASS_FLAG_LASTFRAG;			/*设置最后分组标志*/
		ipr->datagram_len = offset + len;				/*设置IP数据报文的全长*/
  	}


	/*将当前的数据放到重组链上,并更新状态*/
	struct skbuff *skb_prev=NULL, *skb_cur=NULL;
	int finish =0;
	void *pos = NULL;
	__u32 length = 0;
#define FRAG_OFFSET(iph) (ntohs(iph->frag_off & 0x1FFF)<<3)
#define FRAG_LENGTH(iph) (ntohs(iph->tot_len) - IPHDR_LEN)
	for(skb_prev =NULL, skb_cur=ipr->skb,length = 0,found = 0;
		skb_cur != NULL && !found;
		skb_prev=skb_cur,skb_cur = skb_cur->next)
	{
		if(skb_prev !=NULL)									/*不是第一个分片*/
		{
			if((offset  < FRAG_OFFSET(skb_cur->nh.iph))			/*接收数据的偏移值位于前后两个之间*/
				&&(offset > FRAG_OFFSET(skb_prev->nh.iph)))
			{				
				skb->next = skb_cur;							/*将接收到的数据放到此位置*/
				skb_prev->next = skb;

				if(offset + len > FRAG_OFFSET(skb_cur->nh.iph))	/*当前数据与后面的分片数据覆盖?*/
				{
					__u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*计算当前链的数据长度修改值*/
					skb->nh.iph->tot_len = htons(modify);		/*更新当前链长度*/
				}

				if(FRAG_OFFSET(skb_prev->nh.iph) 				/*前面的分片长度覆盖当前数据?*/
					+ FRAG_LENGTH(skb_prev->nh.iph) 
						> FRAG_OFFSET(skb_cur->nh.iph))
				{
					__u16 modify = FRAG_OFFSET(skb_prev->nh.iph) - offset + IPHDR_LEN;/*计算前面数据长度的更改之*/
					skb_prev->nh.iph->tot_len = htons(modify);	/*修改前一片的数据长度*/
				}

				found = 1;									/*找到合适的分片插入位置*/
			}
		}
		else													/*为重组链上的头部*/
		{
			if(offset  < FRAG_OFFSET(skb_cur->nh.iph)){			/*当前链的偏移量小于第一个分片的偏移长度*/
				skb->next = ipr->skb;							/*挂接到重组链的头部*/
				ipr->skb = skb;								
				if(offset + len + IPHDR_LEN 						/*查看是否覆盖后面分片的数据*/
					> FRAG_OFFSET(skb_cur->nh.iph))
					{
					__u16 modify = FRAG_OFFSET(skb_cur->nh.iph) - offset + IPHDR_LEN;/*修改分片的数据长度*/
					if(!offset)								/*偏离量为0*/
						modify -= IPHDR_LEN;					/*包含头部,所以数据段长度需要减去IP头部长度*/

					skb->nh.iph->tot_len = htons(modify);		/*设置分片中修改后的长度*/
				}
			}
		}
		
		length += skb_cur->nh.iph->tot_len - IPHDR_LEN;			/*当前链表中的数据长度*/
	}

	/*重新计算重组链上的总数据长度*/
	for(skb_cur=ipr->skb,length = 0;
		skb_cur != NULL;
		skb_cur = skb_cur->next)
	{
		length += skb_cur->nh.iph->tot_len - IPHDR_LEN;
	}
	length += IPHDR_LEN;
	
	/*全部的IP分片都已经接收到后进行数据报文的重新组合
	数据拷贝到一个新的数据结构中,原来的数据接收都释放掉
	并从分组链中取出,将重组后的数据结构指针返回*/
	if(length == ipr->datagram_len )							/*分组全部接收到?*/
	{
		ipr->datagram_len += IPHDR_LEN;					/*计算数据报文的实际长度长度*/
		skb = skb_alloc(ipr->datagram_len + ETH_HLEN);		/*申请空间*/

		skb->phy.raw = skb_put(skb, ETH_HLEN);			/*物理层*/
		skb->nh.raw = skb_put(skb, IPHDR_LEN);			/*网络层*/
		memcpy(skb->nh.raw, & ipr->iphdr, sizeof(ipr->iphdr));	/*向新数据结构中拷贝IP头*/
		skb->nh.iph->tot_len = htons(ipr->datagram_len);		/*新结构中的tot_len*/
		
		for(skb_prev=skb_cur=ipr->skb;skb_cur != NULL;)		/*遍历重组数据链*/
		{
			int size = skb_cur->end - skb_cur->tail;			/*计算拷贝数据源的长度*/
			pos = skb_put(skb, size);						/*计算拷贝目的地址位置*/
			memcpy(pos, 									/*将一个分片拷贝到新结构中*/
				skb_cur->tail, 
				skb_cur->nh.iph->tot_len - skb_cur->nh.iph->ihl<<2);
		}

		/*一下从重组链中摘除数据并释放,然后设置新结构中的几个IP头部参数*/
		ipr_prev->next = ipr->next;							/*将此数据报文从重组链中摘除*/
		IP_FREE_REASS(ipr);								/*释放此报文的重组连*/
		skb->nh.iph->check = 0;							/*设置校验值为0*/
		skb->nh.iph->frag_off = 0;							/*偏移值为0*/
		skb->nh.iph->check = SIP_Chksum(skb->nh.raw, skb->nh.iph->tot_len);/*计算IP头部校验和*/
	}
	
normal:
	return skb;
freeskb:
	skb_free(skb);
	return NULL;
}