赞
踩
在使用原始套接字发送/接收报文时,需要计算IP/TCP的checksum来验证报文的准确性,网上看了很多开源软件的实现(如SendIP、libdnet、Suricata),感觉SendIP的代码最简单,所以整理如下方便后面使用。
1、sendip: https://github.com/rickettm/SendIP.
checksum计算代码:csum.c
/* Checksum a block of data */ u_int16_t csum (u_int16_t *packet, int packlen) { register unsigned long sum = 0; while (packlen > 1) { sum+= *(packet++); packlen-=2; } if (packlen > 0) sum += *(unsigned char *)packet; /* TODO: this depends on byte order */ while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); return (u_int16_t) ~sum; }
2、IP的checksum计算代码:ipv4.c
static void ipcsum(sendip_data *ip_hdr) {
ip_header *ip = (ip_header *)ip_hdr->data;
ip->check=0;
ip->check=csum((u_int16_t *)ip_hdr->data, ip_hdr->alloc_len);
}
3、TCP的checksum计算代码:tcp.c
static void tcpcsum(sendip_data *ip_hdr, sendip_data *tcp_hdr, sendip_data *data) { tcp_header *tcp = (tcp_header *)tcp_hdr->data; ip_header *ip = (ip_header *)ip_hdr->data; u_int16_t *buf = malloc(12+tcp_hdr->alloc_len+data->alloc_len); u_int8_t *tempbuf = (u_int8_t *)buf; tcp->check=0; if(tempbuf == NULL) { fprintf(stderr,"Out of memory: TCP checksum not computed\n"); return; } /* Set up the pseudo header */ memcpy(tempbuf,&(ip->saddr),sizeof(u_int32_t)); memcpy(&(tempbuf[4]),&(ip->daddr),sizeof(u_int32_t)); tempbuf[8]=0; tempbuf[9]=(u_int16_t)ip->protocol; tempbuf[10]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0xFF00)>>8; tempbuf[11]=(u_int16_t)((tcp_hdr->alloc_len+data->alloc_len)&0x00FF); /* Copy the TCP header and data */ memcpy(tempbuf+12,tcp_hdr->data,tcp_hdr->alloc_len); memcpy(tempbuf+12+tcp_hdr->alloc_len,data->data,data->alloc_len); /* CheckSum it */ tcp->check = csum(buf,12+tcp_hdr->alloc_len+data->alloc_len); free(buf); }
1、测试报文,wireshark简单抓包如下:
2、测试代码,未解析协议直接原始报文计算,checksum_test.c
#include <stdio.h> //gcc -o checksum_test checksum_test.c /* Checksum a block of data */ typedef unsigned short u_int16_t; typedef unsigned char u_int8_t; u_int16_t csum(u_int16_t* packet, int packlen) { register unsigned long sum = 0; //求和 while (packlen > 1) { sum += *(packet++); packlen -= 2; } //因为两个字节合并unsigned short整型做计算,所以如果报文大小为奇数字节则单独加上最后一个字节的数据 if (packlen > 0) sum += *(unsigned char*)packet; /* TODO: this depends on byte order */ //如果存在溢出则截断高16位数据与低16位数据求和,如sum=0x0102030405 则sum=0x02030405 + 0x00000001 while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16); //sum取反码 return (u_int16_t)~sum; } int main(int argc, char** argv) { //ip checksum 0x995e /*完整报文 a4 ae 11 17 49 e7 f4 de af ed d0 15 08 00 45 00 //45 00开始IP报文头 00 34 0c 23 40 00 73 06 99 5e d8 3a c8 2a c0 a8 01 35 01 bb e3 a6 6a d5 1e 6b 56 c1 3f c3 80 12 //01 bb开始TCP报文 fa f0 0c ae 00 00 02 04 05 ac 01 03 03 08 01 01 04 02 */ u_int8_t pcaket[] = { 0xa4, 0xae, 0x11, 0x17, 0x49, 0xe7, 0xf4, 0xde, 0xaf, 0xed, 0xd0, 0x15, 0x08, 0x00, 0x45, 0x00, //45 00开始IP报文头 0x00, 0x34, 0x0c, 0x23, 0x40, 0x00, 0x73, 0x06, 0x99, 0x5e, 0xd8, 0x3a, 0xc8, 0x2a, 0xc0, 0xa8, 0x01, 0x35, 0x01, 0xbb, 0xe3, 0xa6, 0x6a, 0xd5, 0x1e, 0x6b, 0x56, 0xc1, 0x3f, 0xc3, 0x80, 0x12, //01 bb开始TCP报文 0xfa, 0xf0, 0x0c, 0xae, 0x00, 0x00, 0x02, 0x04, 0x05, 0xac, 0x01, 0x03, 0x03, 0x08, 0x01, 0x01, 0x04, 0x02 }; //先将校验和置为0,然后两个字节合并unsigned short整型 u_int16_t packet_ip_wichout_checksum[10] = { 0x4500,0x0034,0x0c23,0x4000,0x7306,0x0000,0xd83a,0xc82a,0xc0a8,0x0135 }; u_int16_t packet_ip_wich_checksum[10] = { 0x4500,0x0034,0x0c23,0x4000,0x7306,0x995e,0xd83a,0xc82a,0xc0a8,0x0135 }; u_int16_t ip_checksum = csum(packet_ip_wichout_checksum, 20); printf("ip checksum:0x%04x\n", ip_checksum); ip_checksum = csum(packet_ip_wich_checksum, 20); printf("ip checksum:0x%04x\n", ip_checksum); //tcp checksum 0x0cae /* Set up the pseudo header */ //前12个字节:4字节IP源地址+4字节IP目的地址+一个字节0+一个字节TCP协议(6)+2个字节(TCP头长度+数据长度) //前12字节为0xd83a,0xc82a,0xc0a8,0x0135,0x0006,0x0020 //01 bb e3 a6 6a d5 1e 6b 56 c1 3f c3 80 12 u_int16_t packet_tcp_wichout_checksum[22] = { 0xd83a,0xc82a,0xc0a8,0x0135,0x0006,0x0020, 0x01bb,0xe3a6,0x6ad5,0x1e6b,0x56c1,0x3fc3,0x8012, 0xfaf0,0x0000,0x0000,0x0204,0x05ac,0x0103,0x0308,0x0101, 0x0402 }; //先将校验和置为0,然后两个字节合并unsigned short整型 u_int16_t packet_tcp_wich_checksum[22] = { 0xd83a,0xc82a,0xc0a8,0x0135,0x0006,0x0020, 0x01bb,0xe3a6,0x6ad5,0x1e6b,0x56c1,0x3fc3,0x8012, 0xfaf0,0x0cae,0x0000,0x0204,0x05ac,0x0103,0x0308,0x0101, 0x0402 }; u_int16_t tcp_checksum = csum(packet_tcp_wichout_checksum, 44); printf("tcp checksum:0x%04x\n", tcp_checksum); tcp_checksum = csum(packet_tcp_wich_checksum, 44); printf("tcp checksum:0x%04x\n", tcp_checksum); return 0; }
编译:gcc -o checksum_test checksum_test.c
运行:./checksum_test
结果如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。