ZC: 貌似 Linux内核里面有 计算何种协议的checksum的函数,但是 应用层 我没有找到现成的函数可供调用...
ZC: IP头的checksum 和 UDP头的checksum 来自于“<<Windows 网络与通信程序设计>> (第2版) 第6章 6.3.3、原始UDP封包发送实例” (6.5 中也有 TCP头checksum的计算方式,不过它是通过TCP伪头来计算的...我没用它...)
ZC: “<<Windows 网络与通信程序设计>> (第2版) 第9章 9.4、互联网计算机扫描”中 有 TCP头checksum的计算方式
1、ip checksum
2、udp checksum
3、tcp checksum
4、代码 来源为<<Windows 网络与通信程序设计>> (第2版) ,从VC6的代码修改而来,实际测试过 下面两个函数是OK的
#include <stdlib.h> #include <string.h> #include <netinet/ip.h> #include <netinet/udp.h> unsigned short checksum(unsigned short* _buff, int _size) { unsigned long cksum = 0; while(_size>1) { cksum += *_buff++; _size -= sizeof(unsigned short); } // 是奇数 if(_size) { cksum += *(unsigned char*)_buff; } // 将32位的chsum高16位和低16位相加,然后取反 cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (unsigned short)(~cksum); } /* 计算UDP伪头校验和。UDP校验和基于如下几个域: 源IP地址 目的IP地址 8位0域 8位协议域 16位UDP长度 16位源端口号 16位目的端口号 16位UDP封包长度 16位UDP校验和(0) UDP净荷 */ void ComputeUdpPseudoHeaderChecksum( struct iphdr *_pIphdr, struct udphdr *_pUdphdr, char *_payload, int _payloadlen ) { char buff[1024]; char *ptr = buff; int chksumlen = 0; unsigned long zero = 0; // 包含源IP地址和目的IP地址 memcpy(ptr, &_pIphdr->saddr, sizeof(_pIphdr->saddr)); ptr += sizeof(_pIphdr->saddr); chksumlen += sizeof(_pIphdr->saddr); memcpy(ptr, &_pIphdr->daddr, sizeof(_pIphdr->daddr)); ptr += sizeof(_pIphdr->daddr); chksumlen += sizeof(_pIphdr->daddr); // 包含8位0域 memcpy(ptr, &zero, 1); ptr += 1; chksumlen += 1; // 协议 memcpy(ptr, &_pIphdr->protocol, sizeof(_pIphdr->protocol)); ptr += sizeof(_pIphdr->protocol); chksumlen += sizeof(_pIphdr->protocol); // UDP长度 memcpy(ptr, &_pUdphdr->len, sizeof(_pUdphdr->len)); ptr += sizeof(_pUdphdr->len); chksumlen += sizeof(_pUdphdr->len); // UDP源端口号 memcpy(ptr, &_pUdphdr->source, sizeof(_pUdphdr->source)); ptr += sizeof(_pUdphdr->source); chksumlen += sizeof(_pUdphdr->source); // UDP目的端口号 memcpy(ptr, &_pUdphdr->dest, sizeof(_pUdphdr->dest)); ptr += sizeof(_pUdphdr->dest); chksumlen += sizeof(_pUdphdr->dest); // 又是UDP长度 memcpy(ptr, &_pUdphdr->len, sizeof(_pUdphdr->len)); ptr += sizeof(_pUdphdr->len); chksumlen += sizeof(_pUdphdr->len); // 16位的UDP校验和,置为0 memcpy(ptr, &zero, sizeof(unsigned short)); ptr += sizeof(unsigned short); chksumlen += sizeof(unsigned short); // 净荷 memcpy(ptr, _payload, _payloadlen); ptr += _payloadlen; chksumlen += _payloadlen; // 补齐到下一个16位边界 for(int i=0; i<_payloadlen%2; i++) { *ptr = 0; ptr++; chksumlen++; } // 计算这个校验和,将结果填充到UDP头 _pUdphdr->check = checksum((unsigned short*)buff, chksumlen); }
5、代码 来源为<<Windows 网络与通信程序设计>> (第2版) 第9章,从VC6的代码修改而来,编译通过 但是 没有 实际测试过 ...(待测试)
/* 计算TCP伪头校验和。TCP校验和基于如下几个域: 源IP地址 目的IP地址 8位0域 8位协议域 16位TCP长度 TCP头 TCP数据 */ void ComputeTcpPseudoHeaderChecksum( struct iphdr *_pIphdr, struct tcphdr *_pTcphdr, char *_payload, int _payloadlen ) { char buff[1024]; char *ptr = buff; int chksumlen = 0; unsigned long zero = 0; // 伪头 // 包含源IP地址和目的IP地址 memcpy(ptr, &_pIphdr->saddr, sizeof(_pIphdr->saddr)); ptr += sizeof(_pIphdr->saddr); chksumlen += sizeof(_pIphdr->saddr); memcpy(ptr, &_pIphdr->daddr, sizeof(_pIphdr->daddr)); ptr += sizeof(_pIphdr->daddr); chksumlen += sizeof(_pIphdr->daddr); // 包含8位0域 memcpy(ptr, &zero, 1); ptr += 1; chksumlen += 1; // 协议 memcpy(ptr, &_pIphdr->protocol, sizeof(_pIphdr->protocol)); ptr += sizeof(_pIphdr->protocol); chksumlen += sizeof(_pIphdr->protocol); // TCP长度 unsigned short tcp_len = htons(sizeof(struct tcphdr) + _payloadlen); memcpy(ptr, &tcp_len, sizeof(tcp_len)); ptr += sizeof(tcp_len); chksumlen += sizeof(tcp_len); // TCP头 memcpy(ptr, _pTcphdr, sizeof(struct tcphdr)); ptr += sizeof(struct tcphdr); chksumlen += sizeof(struct tcphdr); // 净荷 memcpy(ptr, _payload, _payloadlen); ptr += _payloadlen; chksumlen += _payloadlen; // 补齐到下一个16位边界 for(int i=0; i<_payloadlen%2; i++) { *ptr = 0; ptr++; chksumlen++; } // 计算这个校验和,将结果填充到TCP头 _pTcphdr->check = checksum((unsigned short*)buff, chksumlen); }
6、
7、
8、