ip头和tcp头checksum计算方法

ip头和tcp头checksum计算方法

最近需要用到ip头和tcp头重新校验,已生成对应的pcap包。网上搜索了下,貌似没有细化的实现。

只有根据各种片段,实现了。 主要填充代码,从sendip开源软件的tcpv4_csum修改而来。

 

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <unistd.h>

#include <signal.h>

#include <vector>

#include <sys/socket.h>

#include <sys/ioctl.h>

#include <netpacket/packet.h> //sockaddr_ll struct

#include <net/if.h> //ifreq struct

#include <linux/ip.h>

#include <linux/if_ether.h>

#include <linux/tcp.h>

#include <netinet/in.h> //htons

#include <netinet/if_ether.h> //ether_header struct

//计算IP校验和

unsigned short checksum(unsigned short *buffer,int size)

{

unsigned long cksum=0;

while(size>1)

{

cksum+=*buffer++;

size-=sizeof(unsigned short);

}

if(size)

{

cksum+=*(unsigned char *)buffer;

}

//将32位数转换成16

while (cksum>>16)

cksum=(cksum>>16)+(cksum & 0xffff);

return (unsigned short) (~cksum);

}

 

void tcpv4_check_addr( __u16 * ppkgdata )

 

{

const int MaxEthFrame=1514;

char * indata;

__u16 ippktlen, udppktlen,tcppktlen,wd;

__u32 ipheadlen;

struct iphdr * ipd;

struct tcphdr * tcpd;

struct udphdr * udpd;

__u16 * databegin;

indata = (char *)ppkgdata; //从MAC开始的整个帧

ipheadlen = 14 + (indata[14]&0x0f)*4 ; //MAC和ip头的长度和

databegin = (__u16 *)(indata + ipheadlen); //ip数据

ipd = (struct iphdr *)(indata + 14); //MAC数据

tcpd = (struct tcphdr *)(indata + ipheadlen); //ip数据

ippktlen = htons(ipd->tot_len); //ip头和ip数据的总长度

 

if(ipd->protocol == 0x6){

tcppktlen = ippktlen +14 - ipheadlen; //tcp头和tcp数据的总长度

printf("ip checksum:%x,sport:%x ",ipd->check,ipd->saddr);

ipd->check = 0;

ipd->check =  checksum((unsigned short *)ipd,ipheadlen-14);

 

printf("end ip checksum:%x,sport:%x ",ipd->check,ipd->saddr);

printf("tcp checksum:%x ",tcpd->check);

 

if (tcppktlen > MaxEthFrame) {

fprintf(stderr,"Tcplen greater than MaxEthFrame(%d) ,real:%d. ",MaxEthFrame,tcppktlen);

return;

}

 

u_int16_t * buf = (__u16 *)malloc(MaxEthFrame);

u_int8_t *tempbuf = (u_int8_t *)buf;

tcpd->check=0;

if(tempbuf == NULL) {

fprintf(stderr,"Out of memory: TCP checksum not computed ");

return;

}

 

/* Set up the pseudo header */

memcpy(tempbuf,&(ipd->saddr),sizeof(u_int32_t));

memcpy(&(tempbuf[4]),&(ipd->daddr),sizeof(u_int32_t));

tempbuf[8]=0;

tempbuf[9]=(u_int16_t)ipd->protocol;

//tempbuf[10]=(u_int16_t)((indata[14]&0x0f)*4);//ip头长度

//tempbuf[11]=(u_int16_t)(tcppktlen);//tcp 头 + data

tempbuf[10]=(u_int16_t)( tcppktlen &0xFF00)>>8;

tempbuf[11]=(u_int16_t)( tcppktlen &0x00FF);

 

/* Copy the TCP header and data */

memcpy(tempbuf+12,tcpd,tcppktlen);

//memcpy(tempbuf+12+tcp_hdr->alloc_len,data->data,data->alloc_len);

 

/* printf("tcppktlen:%d,iphlen:%d,content: ",tcppktlen,(indata[14]&0x0f)*4);

for(int i=0;i<tcppktlen+12;i++){

printf("%02x ",tempbuf[i]);

if((i+1) % 16 ==0) printf(" ");

}

printf(" ");

*/

/* CheckSum it */

tcpd->check = checksum((__u16 *)buf,12+tcppktlen);

free(buf);

 

printf("end tcp checksum:%x ",tcpd->check);

 

}//end tcp

 

}

 

 

int main(int argc,char ** argv){

const int MaxEthFrame=1514;

FILE * fp = fopen(argv[1],"rb");

FILE * fp_save = fopen(argv[2],"wb");

 

u_char * frameBuffer=NULL;

 

if(fp && fp_save){

printf("Read File %s ok.",argv[1]);

frameBuffer = (u_char *)malloc(MaxEthFrame);

 

if(frameBuffer == NULL){

printf("Alloc parket mem failed. ");

}

 

int size =  fread(frameBuffer,sizeof(u_char),MaxEthFrame, fp);

printf("sizeof(u_char):%d,Read %d,content: ",sizeof(u_char),size);

for(int i=0;i<size;i++){

printf("%02x ",frameBuffer[i]);

if((i+1) % 16 ==0) printf(" ");

}

printf(" ");

 

tcpv4_check_addr(( __u16 * )frameBuffer );

 

printf("Change content: ",size);

for(int i=0;i<size;i++){

printf("%02x ",frameBuffer[i]);

if((i+1) % 16 ==0) printf(" ");

}

printf(" ");

 

fwrite(frameBuffer,sizeof(u_char),size,fp_save);

 

free(frameBuffer);

frameBuffer = NULL;

fclose(fp);

fclose(fp_save);

}else{

printf("open failed.");

}

 

return 0;

}
| 0个评论