TCP校验和计算的问题

DeadWolf 2005-06-14 03:55:52
PTCPData(PIP_HEADER pIpHeader,PTCP_HEADER pTcpHeader)
{

WORD checksum,checksumo;
WORD w1,w2;
BYTE *pdata=NULL;
PSDHEADER AddHeader;


AddHeader.saddr = (DWORD)pIpHeader->SourceIp;
AddHeader.daddr = (DWORD)pIpHeader->DestinationIp;
AddHeader.ptcl = pIpHeader->Protocol;
AddHeader.tcpl = pIpHeader->DatagramLength - pIpHeader->HeaderLength*4;
AddHeader.mbz = 0;

w1 = CheckSum((USHORT*)&AddHeader,sizeof(PSDHEADER));

checksum = pTcpHeader->CheckSum ;
pTcpHeader->CheckSum = 0;
w2 = CheckSum((USHORT*)pTcpHeader,AddHeader.tcpl);
checksumo = ~((~w1)+(~w2));


return 0;
}

计算出的校验和 checksumo 和 原来的校验和checksum
怎么会不一致
...全文
2718 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
DeadWolf 2005-06-15
  • 打赏
  • 举报
回复
原因是包的数据部分和包头不在连续的内存段中
DeadWolf 2005-06-15
  • 打赏
  • 举报
回复
发现问题时如果udp或tcp包中包含数据
那么计算的校验和就会不对

有这方面经历的TX吗
DeadWolf 2005-06-15
  • 打赏
  • 举报
回复
EncodeUDPData(PIP_HEADER pIpHeader,PUDP_HEADER pUdpHeader)
{
WORD checksum,checksumo;
DWORD w1,w2,w3;
USHORT size;
BYTE *pdata=NULL;
PSDHEADER AddHeader;

AddHeader.saddr = *(DWORD*)pIpHeader->SourceIp;
AddHeader.daddr = *(DWORD*)pIpHeader->DestinationIp;
AddHeader.ptcl = pIpHeader->Protocol;
size = ntohs(pIpHeader->DatagramLength)- (pIpHeader->HeaderLength*4);

AddHeader.tcpl = ntohs(size);
AddHeader.mbz = 0;

checksum = pUdpHeader->CheckSum ;
pUdpHeader->CheckSum =0;

w1 = CheckSumDW((USHORT*)&AddHeader,sizeof(PSDHEADER));

w2 = CheckSumDW((USHORT*)pUdpHeader,size);
w3=w1+w2;
w3 = (w3 >> 16) + (w3 & 0xffff);
w3 += (w3 >>16);
w3=~w3;

pUdpHeader->CheckSum = checksum;
return 0;
}

TCP 计算正确了
主要问题是包大小忘了字节序的问题
但是同样的代码在给UDP计算的时候又不正确
代码如上,udp和tcp校验和计算有什么区别
DeadWolf 2005-06-14
  • 打赏
  • 举报
回复
发现奇怪问题 pIpHeader->DatagramLength
通常比较大 都是>1024,几十K

怎么就没有小一点的数据呢?
DeadWolf 2005-06-14
  • 打赏
  • 举报
回复
怎么又变成按异或了??
老夏Max 2005-06-14
  • 打赏
  • 举报
回复
对此数据以16比特为单位求反后做按位异或运算
=========================
在计算ICMP,TCP/UDP报文的校验和时为什么要加上伪头标?如何利用伪头标计算校验和?

伪头标的作用:因在校验和中加入了伪头标,故ICMP除能防止单纯数据差错之外,对IP分组也具有保护作用。也就是说,在系统安装的协议中保证接口的正常工作。例如,IP错误地将UDP报文送到ICMP中,因UDP和ICMP使用了相同的校验和算法,对报文内容校验不能防止此报文的误发送。伪头标也校验IP下一个头标值,该值对ICMP和UDP是不同的。结果,利用校验就能保证IP将报文送往预定的上层协议(也就是说,由于UDP和ICMP中伪头标的下个头标值是不同的,即使报文相同,其校验和也不一样,如UDP报文错误地进入ICMP或ICMP报文进入UDP,就会出现校验和差错。 下面以UDP为例叙述伪头标的计算方法: 1 在UDP数据报前加上伪头标。 2 当应用数据为奇数字节时,最后应加上其值为0的字节(在净荷长度和数据长度中不计及此字节)。 3 将校验和域的值置 0。 4 对此数据以16比特为单位求反和做按位异或运算。 5 当求和结果为0时,将校验和置成16进制的FFFF。除此之外的情况,将求得的值原封不动地作为校验和应用。 另外,若校验的是TCP,因为TCP不允许发送方省略检验和,故不需特别对其值为0的校验和进行处理,即可省略验证的步骤1。 1 当校验和的值为0时,就假定是正确的,可省略其余的步骤 (注 1) 2 在UDP数据报头标前加上伪头标。 3 当应用数据为奇数字节时,最后应加上其值为0的字节(在净荷长度和数据报长度中不计及此字节)。 4 对此数据以16比特为单位求反后做按位异或运算。 5 如果求和结果为16进制的FFFF,校验和正确,否则不正确。

DeadWolf 2005-06-14
  • 打赏
  • 举报
回复
rabo(不哭死人)

是每个字节求反再求和
还是每个字求反再求和
qrlvls 2005-06-14
  • 打赏
  • 举报
回复
先把CHKSUM那两位置零,然后把整个TCP包头的每一位求反,然后求合,就得到chksum,再填进去。
我以前在写驱动的时候,也在网上搜索了一些算法,都合上面的差不多,但是结果都是错的。
后来自己按照上面我说的方法写了一个就对了。
------------------------------
正确,即使是加密的话,加密后校验和也是要变化的,否则的话就被系统协议栈丢弃了
bohut 2005-06-14
  • 打赏
  • 举报
回复
mark
老夏Max 2005-06-14
  • 打赏
  • 举报
回复
也许加密了!?
rabo 2005-06-14
  • 打赏
  • 举报
回复
先把CHKSUM那两位置零,然后把整个TCP包头的每一位求反,然后求合,就得到chksum,再填进去。
我以前在写驱动的时候,也在网上搜索了一些算法,都合上面的差不多,但是结果都是错的。
后来自己按照上面我说的方法写了一个就对了。
DeadWolf 2005-06-14
  • 打赏
  • 举报
回复
多谢捧场

我不是要校验和的函数

我是截获系统的TCP包
然后自己在计算了一遍校验和,发现和系统计算的不一致,为什么?

checksum函数的实现和楼上的一样
老夏Max 2005-06-14
  • 打赏
  • 举报
回复
参考:
http://www.vckbase.com/document/viewdoc/?id=652

http://www.pconline.com.cn/pcedu/empolder/gj/vc/0207/78851.html
DeadWolf 2005-06-14
  • 打赏
  • 举报
回复
我是 计算伪首部校验和 w1
,tcp包校验和 w2
总的校验和 =~(~w1+~w2)
但是结果和系统计算的校验和不一致


老夏Max 2005-06-14
  • 打赏
  • 举报
回复
unsigned short checksum(unsigned short *buffer,int size) //校验和的求法
{
unsigned long cksum=0;
while(size>0) //各位求和
{
cksum+=*buffer++;
size-=sizeof(unsigned short);
}
if(size)
cksum+=*(unsigned char *)buffer;
cksum=(cksum>>16)+(cksum & 0xffff); //移位,位与运算
cksum+=(cksum>>16);
return (unsigned short)(~cksum); //再取反
}

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧