修改IP、TCP、UDP校验码

  ipv4数据报文中修改的来源ip或目的ip后,一般需要修改对应的校验码。首先ip校验码是最基础的,然后因为TCP/UDP对应的校验码会根据伪报文头检查(其中包含src ip 和 dst ip),所以也需要修改tcp/udp报文的校验码。这里修复了一些其他文章中的BUG,例如缓存溢出、构造TCP/UDP伪报文采用的参数等,通过实验能够正常运行。

1.IP检验码

unsigned int Checksum(unsigned int cksum, void *pBuffer, unsigned int size)
{
    unsigned int num = 0;
    unsigned char *p = (unsigned char *)pBuffer;
    if ((NULL == pBuffer) || (0 == size))
    {
        return cksum;
    }
    while (size > 1)
    {
        cksum += ((unsigned short)p[num] << 8 & 0xff00) | (unsigned short)(p[num + 1] & 0x00FF);
        size  -= 2;
        num   += 2;
    }
    if (size > 0)
    {
        cksum += ((unsigned short)p[num] << 8) & 0xFFFF;
        num += 1;
    }
    while (cksum >> 16)
    {
        cksum = (cksum & 0xFFFF) + (cksum >> 16);
    }
    return cksum;
}

unsigned short ChangeIpv4Checksum(char *ipHeader)
{
    unsigned short ipHeadLen  = (ipHeader[0] & 0x0F) << 2;
    ipHeader[10] = 0;
    ipHeader[11] = 0;

    unsigned int sum = Checksum(0, (void *)(&ipHeader[0]), ipHeadLen);
    unsigned int tmp = ~sum;

    ipHeader[10] = (unsigned char)(tmp >> 8);
    ipHeader[11] = (unsigned char)(tmp);

    return ipHeadLen;
}

2.TCP/UDP校验码 

  执行修改当前数据包TCP或UDP校验码

//获取Tcp/Udp报文首地址指针,ethPkt表示ipv4报文首地址,0x45 00 .....
unsigned char *header = ðPkt[ipHeadLen];
//计算ipv4报文中Tcp/Udp报文长度
unsigned short len = ntohs(*(unsigned short*)(ðPkt[2])) - ipHeadLen;
//根据修改的源IP或目的IP来计算校验码,ethPkt[9]表示tcp或协议类型
ChangeTcpUdpChecksum(header, source_ip.to_uint(), target_ip.to_uint(), ethPkt[9], len);

  计算TCP或UDP校验码函数,其中构造TCP/UDP伪报头中采用长度为TCP/UDP段之后报文长度,ptc表示采用哪种协议。

Checksum函数和IP一样,都是计算校验和求反。

struct psd_header
{
    unsigned int saddr; //tcp source addr
    unsigned int daddr; //tcp target addr
    char mbz;           //NULL
    char ptcl;          //protocol type
    unsigned short tcpl; //TCP length = headerLen + bodyLen;
};

/*
 * Header tcp/udp header,
 * len is tcp/udp packet length ,contains data segement 这里重点,计算伪报文头的传递长度中包含数据段长度
 * ptc is tcp/udp protocol code ,0x06 to tcp or 0x11 to udp
 * */
void ChangeTcpUdpChecksum(unsigned char *Header, unsigned int ui_source_ip, unsigned int ui_target_ip, char ptc, unsigned short len)
{
    unsigned char SendBuf[2048] = {0};
    unsigned short header_len = (Header[12] & 0xFF) >> 2;

    Header[16]=0;
    Header[17]=0;

    struct psd_header *p_psd = NULL;
    p_psd = (struct psd_header *)malloc(sizeof(struct psd_header));
    p_psd->saddr = (unsigned int)htonl(ui_source_ip);
    p_psd->daddr = (unsigned int)htonl(ui_target_ip);
    p_psd->mbz = (char)0x00;
    p_psd->ptcl = ptc;
    p_psd->tcpl = (unsigned short)htons(len);

    //copy and compute checksum
    memcpy(SendBuf,p_psd,sizeof(struct psd_header));
    memcpy(SendBuf+sizeof(struct psd_header),Header,len);
    unsigned int tcp_sum=Checksum(0,(void *)&SendBuf,sizeof(struct psd_header)+len);
    unsigned int tcp_tmp = ~tcp_sum;
    Header[16]=(unsigned char)(tcp_tmp >> 8);
    Header[17]=(unsigned char)(tcp_tmp);
    free(p_psd);

    return ;
}

参考引用:
https://blog.csdn.net/jiangqin115/article/details/39315085
https://blog.csdn.net/wangshiqilin_fjy/article/details/7889316
https://blog.csdn.net/zhangskd/article/details/11770647

发表评论

邮箱地址不会被公开。 必填项已用*标注