当前位置:   article > 正文

Linux C语言实现TCP/IP的checksum校验和计算_linux tcp checksum

linux tcp checksum

Linux C语言实现TCP/IP的checksum校验和计算

  在使用原始套接字发送/接收报文时,需要计算IP/TCP的checksum来验证报文的准确性,网上看了很多开源软件的实现(如SendIP、libdnet、Suricata),感觉SendIP的代码最简单,所以整理如下方便后面使用。

一、sendip的TCP/IP的checksum计算

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

二、checksum的计算测试

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

编译:gcc -o checksum_test checksum_test.c
运行:./checksum_test
结果如下:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/385986
推荐阅读
相关标签
  

闽ICP备14008679号