IP数据包的校验和算法

1、算法思路:

       IP/ICMP/IGMP/TCP/UDP等协议的校验和算法都是相同的,算法如下:

  在发送数据时,为了计算IP数据包的校验和。应该按如下步骤:
  (1)把IP数据包的校验和字段置为0;
  (2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和;
  (3)把得到的结果存入校验和字段中。
  在接收数据时,计算数据包的校验和相对简单,按如下步骤:
  (1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段;
  (2)检查计算出的校验和的结果是否等于零(反码应为16个0);
  (3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。

  所谓的二进制反码求和,即为先进行二进制求和,然后对和取反。

       计算对IP首部检验和的算法如下:

  (1)把IP数据包的校验和字段置为0;
  (2)把首部看成以16位为单位的数字组成,依次进行二进制求和(注意:求和时应将最高位的进位保存,所以                  加法应采用32位加法);
  (3)将上述加法过程中产生的进位(最高位的进位)加到低16位(采用32位加法时,即为将高16位与低16位                   相加,之后还要把该次加法最高位产生的进位加到低16位)
  (4)将上述的和取反,即得到校验和。

2、实现范例:

       汇编:这个可以在linux内核代码里找到,下面就是 arch/x86/include/asm/checksum_32.h里面的内容:

/*
 *	This is a version of ip_compute_csum() optimized for IP headers,
 *	which always checksum on 4 octet boundaries.
 *
 *	By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
 *	Arnt Gulbrandsen.
 */
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
	unsigned int sum;

	asm volatile("movl (%1), %0	;\n"
		     "subl $4, %2	;\n"
		     "jbe 2f		;\n"
		     "addl 4(%1), %0	;\n"
		     "adcl 8(%1), %0	;\n"
		     "adcl 12(%1), %0;\n"
		     "1:	adcl 16(%1), %0	;\n"
		     "lea 4(%1), %1	;\n"
		     "decl %2	;\n"
		     "jne 1b		;\n"
		     "adcl $0, %0	;\n"
		     "movl %0, %2	;\n"
		     "shrl $16, %0	;\n"
		     "addw %w2, %w0	;\n"
		     "adcl $0, %0	;\n"
		     "notl %0	;\n"
		     "2:		;\n"
	/* Since the input registers which are loaded with iph and ihl
	   are modified, we must also specify them as outputs, or gcc
	   will assume they contain their original values. */
		     : "=r" (sum), "=r" (iph), "=r" (ihl)
		     : "1" (iph), "2" (ihl)
		     : "memory");
	return (__force __sum16)sum;
}
          C语言:很多网络协议都用如下代码实现校验和算法:

/*求校验和函数*/
USHORT CheckSum(USHORT *buffer, int size)
{
	unsigned long cksum=0;
    while (size > 1) 
    {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }
    if (size) 
    {
        cksum += *(UCHAR*)buffer;
    }
	/*对每个16bit进行二进制反码求和*/
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (USHORT)(~cksum);
}

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IP数据报的校验和算法是一种很重要的数据包完整性校验手段,该算法IP数据的发送和接收过程中都得到广泛应用。 该算法的实现步骤如下: 1. 首先将整个IP数据包的首部按照16bit一组进行分组,不足16bit且不是末尾则在末尾添加0 2. 将这些16bit的数字从第一个到最后一个相加,得到一个数值 3. 以32位为单位将这个数值进行反码运算,得到的结果即为校验和 参考样例代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #define BUFFERSIZE 32 /* * 计算IP数据包首部的校验和 * @param buf 待计算数据包首部 "struct ipheader" 的指针 * @param len 数据包首部长度 (单位:bytes) * return 计算得到的校验和 */ unsigned short checksum(unsigned short *buf, int len){ unsigned long sum = 0; while(len > 1){ sum += *buf++; len -= 2; } if(len){ sum += *(unsigned char*)buf; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return (unsigned short)(~sum); } struct ipheader{ unsigned char ver_ihl; /* 版本 (4 bits) + 首部长度 (4 bits) */ unsigned char tos; /* 服务类型(Type of Service) */ unsigned short total_len; /* 总长(Total Length) */ unsigned short ident; /* 标识(Identification) */ unsigned short frag_and_flags; /* 标志位(Flags) (3 bits) + 片偏移(Fragment offset) (13 bits) */ unsigned char ttl; /* 存活时间(Time to live) */ unsigned char protocol; /* 协议(Protocol) */ unsigned short checksum; /* 首部校验和(Header checksum) */ unsigned int sourceIP; /* 源IP地址(Source IP address) */ unsigned int destIP; /* 目的IP地址(Destination IP address) */ }; int main(){ unsigned char buffer[BUFFERSIZE]; memset(buffer,0,BUFFERSIZE); struct ipheader *ip = (struct ipheader*) buffer; ip->ver_ihl = 0x45; ip->tos = 0; ip->total_len = htons(sizeof(struct ipheader)); ip->ident = htons(54321); ip->frag_and_flags = 0; ip->ttl = 128; ip->protocol = 6; ip->checksum = 0; ip->sourceIP = inet_addr("192.168.1.101"); ip->destIP = inet_addr("192.168.1.1"); unsigned short check_sum = checksum((unsigned short*)ip,sizeof(struct ipheader)); printf("check sum=%d\n",check_sum); ip->checksum = check_sum; return 0; } 该程序首先定义了一个结构体ipheader,该结构体包含了一个完整的IP首部,然后通过调用checksum函数计算IP数据包首部的校验和。最后将计算得到的校验和存入IP首部中的checksum字段。运行该程序后即可得到IP数据包首部的校验和

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值