IP数据包的校验和算法(载))

合集下载

计算机网络试卷14

计算机网络试卷14

《计算机网络》试卷14一、填空(10分,每空1分)1.域名系统DNS使用的端口号是___________。

2.地址192.168.86.0/28中有___________个可用的子网和____________台可用的主机。

3.按交换方式来分类,计算机网络可以分为__________、__________和__________三种。

4.__________、__________和__________是二进制数据编码技术中的三种主要编码方案。

5. 802.3以太网最大可传送的帧(数据)长度为___________个8位组。

二、单项选择题(30分,每题2分)1.ARP协议的作用是()。

A. 将端口号映射到IP 地址B. 连接IP 层和TCP 层C. 广播IP 地址D. 将IP 地址映射到第二层地址2.100BASE-TX使用()传输介质。

A. 双绞线B. 同轴电缆C. 红外线D. 光纤3.在二进制指数后退算法中,如果发生了11次碰撞之后,那么站点会在0和()之间选择一个随机数。

A. 511B. 1023C. 2047D. 14.EI载波把32个信道按时分多路方式复用在一条2.048 Mb/s 的高速信道上,每条话音信道的数据速率是()A. 56Kb/sB. 64Kb/sC. 128Kb/sD. 512Kb/s5.如果用户网络需要划分成5个子网,每个子网最多20台主机,则适用的子网掩码是()A. 255.255.255.192B. 255.255.255.224C.255.255.255.240D. 255.255.255.2486.局域网的英文缩写为()。

A. WANNC.SAND.MAN7.ARP请求是采用()方式发送的。

A.单播B.组播C. 广播D. 点播8.TCP协议使用()次握手机制建立连接。

A. 1B.2C. 3D. 49.在同一个信道上的同一时刻,能够进行双向数据传送的通信方式是()。

A. 单工B.半双工C. 全双工D. 以上都不是10.SNMPv2提供了3种访问管理信息的方法,这三种方法不包括()。

计算机网络试卷19

计算机网络试卷19

《计算机网络》试卷19一、填空(10分,每空1分)1.域名系统DNS使用的端口号是___________。

2.在采用电信号表达数据的系统中,数据有___________和___________两种。

3.最常见的主动攻击方式有___________、___________和___________。

4.多路复用分为___________、___________和___________。

5. 802.3以太网最大可传送的帧(数据)长度为___________个8位组。

二、单项选择题(30分,每题2分)1.运输层的端口号可分为熟知端口号、注册端口号和()。

A. 确认端口号B.永久端口号C. 客户端口号D. 临时端口号2.100BASE-TX使用()传输介质。

A. 双绞线B. 同轴电缆C. 红外线D. 光纤3.在二进制指数后退算法中,如果发生了11次碰撞之后,那么站点会在0和()之间选择一个随机数。

A. 511B. 1023C. 2047D. 14.EI载波把32个信道按时分多路方式复用在一条2.048 Mb/s 的高速信道上,每条话音信道的数据速率是()A. 56Kb/sB. 64Kb/sC. 128Kb/sD. 512Kb/s5.如果用户网络需要划分成5个子网,每个子网最多20台主机,则适用的子网掩码是()A. 255.255.255.192B. 255.255.255.224C.255.255.255.240D. 255.255.255.2486.若IP数据报在传送过程中,TTL字段等于零,则路由器会发出()A. 超时B.路由重定向C. 目标不可达D. 源站抑制7.ARP请求是采用()方式发送的。

A.单播B.组播C. 广播D. 点播8.TCP协议使用()次握手机制建立连接。

A. 1B.2C. 3D. 49.在同一个信道上的同一时刻,能够进行双向数据传送的通信方式是()。

A. 单工B.半双工C. 全双工D. 以上都不是10.SNMPv2提供了3种访问管理信息的方法,这三种方法不包括()。

解析IP数据包

解析IP数据包

解析IP数据包IP数据包是在互联网传输中扮演重要角色的一种数据格式。

它包含了源IP地址和目标IP地址,以及其他与网络通信相关的信息。

解析IP数据包是对这些信息进行分析和解读的过程,以便理解数据包的来源、目的和内容。

在解析IP数据包时,我们可以从以下几个方面进行详细的分析:1. 版本号:IP数据包的版本号指示了所使用的IP协议的版本。

常见的版本有IPv4和IPv6。

IPv4是目前广泛使用的版本,而IPv6是为了解决IPv4地址不足的问题而推出的新版本。

2. 头部长度:IP数据包的头部长度指示了IP头部的长度,以字节为单位。

头部长度可以通过该字段的值乘以4来计算得到实际长度。

3. 服务类型:IP数据包的服务类型字段用于指示对数据包的处理优先级和要求。

这个字段可以用于区分不同类型的流量,如语音、视频或者普通数据。

4. 总长度:IP数据包的总长度字段指示了整个IP数据包的长度,包括头部和数据部份。

这个字段的值以字节为单位。

5. 标识、标志和片偏移:IP数据包的标识字段用于惟一标识一个IP数据包。

标志字段用于指示是否还有后续的分片数据包,以及是否允许分片。

片偏移字段用于指示当前数据包在原始数据中的位置。

6. 生存时间:生存时间字段指示了IP数据包在网络中的最大生存时间。

每经过一个路由器,生存时间字段的值就会减少1。

当生存时间字段的值为0时,数据包将被丢弃。

7. 协议:协议字段指示了IP数据包中封装的上层协议类型。

常见的协议有TCP、UDP和ICMP等。

8. 校验和:校验和字段用于检测IP数据包在传输过程中是否发生了错误。

发送端会计算校验和,并将其添加到IP头部中。

接收端在接收到数据包后会重新计算校验和,并将其与接收到的校验和进行比较,以检测数据包是否有损坏。

9. 源IP地址和目标IP地址:源IP地址字段指示了数据包的发送者的IP地址,而目标IP地址字段指示了数据包的接收者的IP地址。

通过解析IP数据包,我们可以获得有关网络通信的重要信息,如数据包的源地址、目标地址、协议类型等。

ip校验规则

ip校验规则

ip校验规则一、IP校验规则简介IP校验规则是指用于验证IP地址格式和范围的规则,以确保网络通信的顺畅进行。

IP地址是互联网上设备之间互相通信的唯一标识,因此IP校验规则在保证网络稳定运行中起着至关重要的作用。

二、IP地址分类与表示方法1.IPV4地址IPV4地址是互联网最常用的地址类型,它采用32位二进制表示,总共分为A、B、C、D、E五类。

其中,A类地址范围为1.0.0.0至126.255.255.255,B类地址范围为128.0.0.0至191.255.255.255,C类地址范围为192.0.0.0至223.255.255.255,D类地址为组播地址,范围为224.0.0.0至239.255.255.255,E类地址为保留地址,范围为240.0.0.0至255.255.255.255。

2.IPV6地址IPV6地址是下一代互联网地址,采用128位二进制表示。

相较于IPV4,IPV6具有更多的地址空间,提高了网络安全性和隐私保护能力。

IPV6地址分为单播、组播和任播三种类型,用于不同场景的通信。

三、IP校验算法1.子网掩码子网掩码是一种用于划分IP地址的网络部分和主机部分的算法。

通过子网掩码,可以将一个大型网络划分为多个较小的子网,提高IP地址的利用率。

子网掩码通常用一个32位的二进制数表示,其中网络部分为1,主机部分为0。

2.CIDR(无类别域间路由)CIDR是一种用于表示网络地址的编码方式,它将IP地址和子网掩码合并为一个统一的表示形式。

CIDR地址格式为“IP地址/子网掩码”,如“192.168.1.0/24”。

CIDR有效地简化了网络地址的表示和计算,便于网络管理和规划。

3.网络层协议校验网络层协议校验是指对IP数据报进行校验,确保数据在传输过程中不被篡改。

主要方法有校验和算法、加密算法等。

这些算法可以检测到数据报在传输过程中的错误,保证数据完整性。

四、IP校验实例与应用1.网络诊断与故障排查通过IP校验规则,可以快速定位网络故障,如IP地址冲突、子网划分不当等问题。

IP 首部校验和的计算 zz

IP 首部校验和的计算 zz

IP 首部校验和的计算zz1IP数据包的头信息格式:+-------------------------------------------------+| 版本 (4位) |+-------------------------------------------------+| 首部长度(4位) |+-------------------------------------------------+| 服务类型(TOS)8位 |+-------------------------------------------------+| 数据包总长度(16位) |+-------------------------------------------------+| 标识ID号(16位) |+-------------------------------------------------+| 标志位(3位) |+-------------------------------------------------+| 片偏移(13位) |+-------------------------------------------------+| 生存时间(TTL)(8位) |+-------------------------------------------------+| 协议类型 (8位) |+-------------------------------------------------+| 首部校验和(16位) |+-------------------------------------------------+| 源IP地址(32位) |+-------------------------------------------------+| 目的IP地址 (32位) |+-------------------------------------------------+* IP选项(若有) (32位) *+-------------------------------------------------+* 数据 *+-------------------------------------------------+这里要说的是首部校验和字段。

IP校验和计算

IP校验和计算

IP校验和‎计算下‎面摘自《T‎C P/IP‎协议簇》的‎I P头校验‎和算法:‎发送时:‎1. ‎将校验和字‎段置为0;‎2. ‎将整个首部‎分为16b‎i t的部分‎,求和;‎3. 取‎反码,填入‎到校验和字‎段中;‎接收时:‎1. 直‎接将整个首‎部分为16‎b it的部‎分,求和;‎2. ‎取反码,若‎结果为0,‎取合法;否‎则丢弃;‎这上面有‎两个细节没‎有描述清楚‎:1.‎计算时的‎字节顺序(‎l itte‎r end‎i an和b‎i g en‎d ian)‎问题;‎2. 取和‎溢出时的改‎进计算方法‎;根据‎实验结果,‎及参考网络‎上的资料,‎实际上几乎‎现有所有的‎系统对校验‎和算法已经‎有点小小的‎补充,也许‎《TCP/‎I P协议簇‎》这里没有‎更新罢了,‎自我安慰吧‎,如下:‎◆当发送‎I P包时,‎需要计算I‎P报头的校‎验和:‎1、把‎校验和字段‎置为0;‎2、‎对IP头部‎中的每16‎b it进行‎二进制求和‎;3、‎如果和‎的高16b‎i t不为0‎,则将和的‎高16bi‎t和低16‎b it反复‎相加,直到‎和的高16‎b it为0‎,从而获得‎一个16b‎i t的值;‎4、‎将该16‎b it的值‎取反,存入‎校验和字段‎。

◆当‎接收IP包‎时,需要对‎报头进行确‎认,检查I‎P头是否有‎误,算法同‎上2、3步‎,然后判断‎取反的结果‎是否为0,‎是则正确,‎否则有错。

‎算法:‎‎‎u nsig‎n ed s‎h ort ‎C heck‎S um(u‎n sign‎e d sh‎o rt *‎_pBuf‎f, in‎t _Si‎z e)‎‎ {‎‎‎unsi‎g ned ‎i nt c‎k Sum ‎= 0;‎‎‎ un‎s igne‎d sho‎r t *t‎m pBuf‎f = _‎p Buff‎;‎‎ i‎n t tm‎p Size‎= _S‎i ze;‎‎‎ wh‎i le (‎t mpSi‎z e > ‎1)‎‎‎{‎‎‎ ck‎S um +‎= *tm‎p Buff‎++;‎‎‎‎tmpS‎i ze -‎= siz‎e of(u‎n sign‎e d sh‎o rt);‎‎‎ }‎‎‎ if‎(tmp‎S ize ‎> 0)‎‎‎ {‎‎‎‎c kSum‎+= *‎(unsi‎g ned ‎c har*‎)tmpB‎u ff;‎‎‎ }‎‎‎ ckS‎u m = ‎(ckSu‎m >> ‎16) +‎(ckS‎u m & ‎0xFFF‎F); /‎/将高16‎b it与低‎16bit‎相加‎‎‎c kSum‎+= (‎c kSum‎>> 1‎6); /‎/将进位到‎高位的16‎b it与低‎16bit‎再相加‎‎‎ re‎t urn ‎(unsi‎g ned ‎s hort‎)(~ck‎S um);‎‎ }‎关于计‎算时的字节‎顺序,一般‎以网络字节‎顺序(bi‎g end‎i an)为‎准,但仍然‎有个十分模‎糊的地方,‎就是为什么‎校验和这个‎字段不用进‎行网络转换‎了,如X8‎6系统,直‎接以本地字‎节顺序(l‎i tter‎endi‎a n)发送‎就可以了,‎这也让我十‎分纠结。

IP和TCP包头校验和计算方法

IP和TCP包头校验和计算方法



TCP 伪首部: c0 a8 01 10 源地址 c0 a8 01 67 目的地址 00 06 00 18 置空,协议类型,TCP 长度
计算: c0a8 0110 c0a8 0167 0006 0018 0401 0578 0000 0000 0000 0000 6002 0fca 0000 0000 0204 0fca c0a8 0110 c0a8 0167 0006 0018 0401 0578 0000 0000 0000 0000 6002 0fca F105 0000 0204 0fca

校验和的算法: (如果数据长度为奇数,最后一个字节要先变成 将数据以字为单位进行累加计算,得到一个双字的值。 字,然后在加到原来的双字中) 将得到的双字的值的高 16 位和低 16 位反复相加,直到高 16 位为 0,然后取低 16 位的值,再将这个 16 位的值取反就得到校验和的值。 实例: IP 头: 45 00 00 31 89 F5 00 00 6E 06 00 00(校验字段) DE B7 45 5D -> 222.183.69.93 C0 A8 00 DC -> 192.168.0.220 计算: 4500 0031 89F5 0000 6e06 0000 DEB7 455D C0A8 00DC =7 = DD38 应填充的校验和 在接收端接收到 IP 数据包后,要对 IP 头进行检查看是否有误,所用的算法与上面一致,不同的是最终的结 果要为 0。 计算: 4500 0031 89F5 0000 6E06 DD38 DEB7 455D C0A8 00DC =3 FFFC 0003 FFFC = FFFF ~ FFFF = 00000 正确 TCP 首部检验和与 IP 首部校验和的计算方法相同,在程序中使用同一个函数来计算。 需要注意的是,由于 TCP 首部中不包含源地址与目标地址等信息,为了保证 TCP 校验的有效性,在进行 TCP 校验和的计算时,需要增加一个 TCP 伪首部的校验和。 定义 TCP 伪首部如下: struct{ unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz;//置空,0x00 char ptcl; //协议类型,0x06 unsigned short tcpl; //TCP 长度,0x0018 } psd_header; 然后我们将这两个字段(TCP 伪首部 + TCP 首部)复制到同一个缓冲区 SendBuf 中并计算 TCP 校验 和: memcpy(SendBuf,&psd_header,sizeof(psd_header)); memcpy(SendBuf sizeof(psd_header),&tcp_header,sizeof(tcp_header)); tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header) sizeof(tcp_header)); 实例: TCP 首部: 04 01 05 78 00 00 00 00 00 00 00 00 60 02 0f ca 00 00 00 00 02 04 0f ca

IP首部检验和的算法

IP首部检验和的算法

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

其中,二进制反码求和的计算方法:首先,计算如图B-1所示的部分和。

把每一列相加,如果有进位,就加到下一列。

注意以下几点:1------------------------第16列的进位1 1------------------------第15列的进位| 1| 1 0| | 1 1| | | 1 0| | | | 1 0| | | | | 1 1| | | | | | | 1 0| | | | | | | | 1 0| | | | | | | | | 1 1| | | | | | | | | | 1 1| | | | | | | | | | 1 0 0-----------第3列的进位| | | | | | | | | | | 1 0 0-----------第2列的进位| | | | | | | | | | | | | 1 1---------第1列的进位| | | | | | | | | | | | | | |1 0 0 1 1 0 0 1 0 0 0 1 0 0 1 00 0 0 0 1 0 0 0 0 1 1 0 1 0 0 11 0 1 0 1 0 1 1 0 0 0 0 0 0 1 00 0 0 0 1 1 1 0 0 0 0 0 1 0 1 00 0 0 0 0 0 0 0 0 0 0 1 0 0 0 10 0 0 0 0 0 0 0 0 0 0 0 1 1 1 10 0 0 0 0 1 0 0 0 0 1 1 1 1 1 10 0 0 0 0 0 0 0 0 0 0 0 1 1 0 10 0 0 0 0 0 0 0 0 0 0 0 1 1 1 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 1 0 1 0 1 0 0 0 1 0 0 0 1 0 10 1 0 1 0 0 1 1 0 1 0 1 0 1 0 00 1 0 0 1 0 0 1 0 1 0 0 1 1 1 00 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0__________________________________1 0 0 1 0 1 1 0 1 1 1 0 1 0 0 1 部分和图B-1 二进制记法的部分和1,当我们加第1列(最右边一列)的时候,我们得到7。

校验和计算

校验和计算
法(载)
2007-11-02 10:52
IP数据包的头信息格式: +-------------------------------------------------+ | 版本 (4位) | +-------------------------------------------------+ | 首部长度(4位) | +-------------------------------------------------+ | 服务类型(TOS)8位 | +-------------------------------------------------+ | 数据包总长度(16位) | +-------------------------------------------------+ | 标识ID号(16位) | +-------------------------------------------------+ | 标志位(3位) | +-------------------------------------------------+ | 片偏移(13位) | +-------------------------------------------------+ | 生存时间(TTL)(8位) | +-------------------------------------------------+ | 协议类型 (8位) | +-------------------------------------------------+ | 首部校验和(16位) | +-------------------------------------------------+ | 源IP地址(32位) | +-------------------------------------------------+ | 目的IP地址 (32位) | +-------------------------------------------------+ * IP选项(若有) (32位) * +-------------------------------------------------+ * 数据 * +-------------------------------------------------+ 这里要说的是首部校验和字段。 在发送数据时,为了计算数IP据报的校验和。应该按如下步骤: (1)把IP数据报的校验和字段置为0。 (2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和。 (3)把得到的结果存入校验和字段中。 在接收数据时,计算数据报的校验和相对简单,按如下步骤: (1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。 (2)检查计算出的校验和的结果是否等于零。 (3)如果等于零,说明被整除,校验是和正确。否则,校验和就是错误的,协议栈要抛弃这个数据包。 首先,查看了Linux 2.6内核中的校验算法,使用汇编语言编写的,显然效率要高些。代码如下: unsigned short ip_fast_csum(unsigned char * 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(sum); }

IP首部检验和算法

IP首部检验和算法

IP⾸部检验和算法原创博⽂,转载请注明。

在学习TCP/IP 详解的过程中遇到了不⽌⼀次的关于检验和的概念,在吸取了他⼈理解的前提下,我决定⽤Wireshark 进⾏抓包分析。

⾸先我们得知道IP数据包格式⾸先把检验和字段置为 0 。

然后,对⾸部中每个 16 bit 进⾏⼆进制反码求和(整个⾸部看成是由⼀串 16 bit的字组成),结果存在检验和字段中。

当收到⼀份I P数据报后,同样对⾸部中每个 16 bit进⾏⼆进制反码的求和。

由于接收⽅在计算过程中包含了发送⽅存在⾸部中的检验和,因此,如果⾸部在传输过程中没有发⽣任何差错,那么接收⽅计算的结果应该为全 1。

如果结果不是全1 (即检验和错误),那么I P就丢弃收到的数据报。

但是不⽣成差错报⽂,由上层去发现丢失的数据报并进⾏重传。

再来看看Wireshark抓取结果观察此图,我们可以看到这是⼀个源地址为123.151.152.231 ⽬的地址为10.22.66.206即为本机地址的IP数字报传送。

注意图中标深蓝颜⾊的数字,每当我们点击分类信息时,下⽅的数字就会跟随着发⽣变化,因此我们就可以得到IP数据报的内容。

、解释如下:(本内容部分取⾃)版本号4,占了4位,表⽰ipv4.接下来是包头长度,⼜占了4位,指明ipv4协议包头长度的字节数包含多少个32位。

由于IPv4的包头可能包含可变数量的可选项,所以这个字段可以⽤来确定IPv4数据报中数据部分的偏移位置。

IPv4包头的最⼩长度是20个字节,因此IHL这个字段的最⼩值⽤⼗六进制表⽰就是5(5x4(4个字节32位) = 20字节)。

就是说,它表⽰的是包头的总字节数是4字节的倍数。

图中即为header length为20表⽰是20个字节,所以经过计算此处⽤⼗六进制表⽰为5,⼆进制表⽰为1001。

再往下是服务类型为0x00。

服务类型此处⼀共占了8位,涵义如下:过程字段: 3位,设置了数据包的重要性,取值越⼤数据越重要,取值范围为:0(正常)~ 7(⽹络控制)延迟字段: 1位,取值:0(正常)、1(期特低的延迟)流量字段: 1位,取值:0(正常)、1(期特⾼的流量)可靠性字段: 1位,取值:0(正常)、1(期特⾼的可靠性)成本字段: 1位,取值:0(正常)、1(期特最⼩成本)未使⽤: 1位接着是总长度total length:⼗六进制是0x0028标识字段:占16位。

IP头部校验和计算

IP头部校验和计算

unsigned short checksum(unsigned short *buf, int nword) {unsigned long sum;for(sum = 0; nword > 0; nword--)sum += *buf++;sum = (sum>>16) + (sum&0xffff);sum += (sum>>16);return -sum;}让我们假设一个IP头数据,来解cksum的惑IP头数据:01000101 /*ver_hlen*/00000000 /*tos*/00000000 00000010 /*len*/00000000 00000000 /*id*/00000000 00000000 /*offset*/00000100 /*ttl*/00010001 /*type*/00000000 00000000 /*cksum(0)*/ 01111111 00000000 00000000 00000001 /*sip*/ 01111111 00000000 00000000 00000001 /*dip*/(1)16比特分组;(2)校验和清‘0’(3)求所有16比特之和01000101 00000000 /*ver_hlen*/ 00000000 00000010 /*len*/---------------------01000101 0000001000000000 00000000 /*id*/---------------------01000101 0000001000000000 00000000 /*offset*/---------------------01000101 0000001000000100 00010001 /*ttl*//*type*/---------------------01001001 0001001100000000 00000000 /*cksum(0)*/---------------------01001001 0001001101111111 00000000 /*sip*/---------------------11001000 0001001100000000 00000001 /*sip*/---------------------11001000 0001010001111111 00000000 /*dip*/---------------------101000111 0001010000000000 00000001 /*dip*/---------------------101000111 00010101sum(4)把求得的和模(216-1)00000000 00000001 (sum>>16) 01000111 00010101(sum&0xffff) ---------------------01000111 00010110(5)在(4)的基础上求二进制反码10111000 11101001cksum说白了就是循环加,然后在取反!对方机器调用checksum()计算校验和,如果校验和为0表明IP包传输正确----------------------------------------------------------- 01000101 /*ver_hlen*/00000000 /*tos*/00000000 00000010 /*len*/00000000 00000000 /*id*/00000000 00000000 /*offset*/00000100 /*ttl*/00010001 /*type*/10111000 11101001/*cksum(0)*/01111111 00000000 00000000 00000001 /*sip*/01111111 00000000 00000000 00000001 /*dip*/01000101 0000000000000000 00000010---------------------01000101 0000001000000000 00000000---------------------01000101 0000001000000000 00000000--------------------- 01000101 00000010 00000100 00010001--------------------- 01001001 00010011 10111000 11101001--------------------- 100000001 11111100 01111111 00000000--------------------- 110000000 11111100 00000000 00000001--------------------- 110000000 11111101 01111111 00000000--------------------- 111111111 11111101 00000000 00000001--------------------- 111111111 11111110 sum00000000 00000001 (sum>>16)11111111 11111110 (sum&0xffff)----------------------11111111 11111111~sum00000000 00000000现在我们所用的机器设备大多数是使用二进制补码算法进行计算的。

使用Python计算IP、TCP、UDP校验和

使用Python计算IP、TCP、UDP校验和

使⽤Python计算IP、TCP、UDP校验和IP数据报的校验:IP数据报只需要对数据头进⾏校验,步骤如下:1. 将接收到的数据的checksum字段设置为02. 把需要校验的字段的所有位划分为16位(2字节)的字3. 把所有16位的字相加,如果遇到进位,则将⾼于16字节的进位部分的值加到最低位上,举例,0xBB5E+0xFCED=0x1 B84B,则将1放到最低位,得到结果是0xB84C4. 将所有字相加得到的结果应该为⼀个16位的数,将该数取反则可以得到检验和checksum。

上述第2步中也可以不⽤每次把进位加到低位,可以等所有数据计算结束再将⾼位16个字依次加到低位,直到最后结果是两个字节为⽌,例如所有数据相加后为0xb6e51c2a3,⾸先将其低位2个字节和剩余的⾼位字节相加0xB6E51+0xC2A3=0xC30F4,对得到的再次将低2个字节和剩余的⾼位相加:0x30F4+0XC=0X3100TCP/UDP数据报的校验⼀、下⾯的图是⼀个UDP的检验和所需要⽤到的所有信息,包括三个部分:UDP伪⾸部UDP⾸部UDP的数据部分⾸先解释下伪⾸部的概念,伪⾸部的数据都是从IP数据报头获取的。

其⽬的是让UDP两次检查数据是否已经正确到达⽬的地,只是单纯为了做校验⽤的。

还有⼀个概念⼗分重要,那就是16位UDP总长度,该长度是UDP头和数据的总长度。

剩下的校验算法和IP数据报的校验⽅法⼀致了。

例⼦import structdef check(data):sum=0for i in range(0,len(data),4):val = int(data[i:i+4],16)sum = sum + valsum = sum & 0xffffffffsum = (sum >> 16) + (sum & 0xffff)if sum > 65535:sum = (sum >> 16) + (sum & 0xffff)return 65535-suma = '4500003c00004000400652c00a1a1a163afb88d1'ip_check = check(a)print('ip_check:',hex(ip_check))a='9bd327105919fa3e17da3cbf8018014dd59000000101080a0024a9d043dcc85d5459504520490d0a' #will length = struct.pack('>H',len(a)//2).hex()print(length)if len(a)%4 !=0:a=a+'00'b='c0a8c8010a1a1a16'+'0006'+length+atcp_check= check(b)print('tcp_check:',hex(tcp_check))。

ip首部校验和算法

ip首部校验和算法

实验报告(3)——首部检验和的编程实现一、实验人员二、实验内容和要求(一)实验内容编写一个计算IP报文中首部校验和的程序,并且通过抓包随机选择一个数据报,提取出IP报文首部部分,根据程序计算出校验和的计算值,与报文中检验和对比,检验程序的正确性,计算结果为0保留数据报,否则丢弃。

(二)实验要求1.掌握IP数据报的结构,通过wireshark抓包随机选择一个TCP数据报,提取IP报部分,并找到首部。

2.学习理解并运用IP首部校验和的计算算法,通过程序实现。

三、实验环境Wireshark抓包工具Microsoft visual studio 2010 C#四、实验过程与结果分析(一)实验过程1.利用wireshark抓包分析包格式并提取IP首部(1)IP数据报格式如图1,IP数据报的首部为前20字节。

因为首部校验和的计算只需要IP数据报的首部20个字节即可,数据部分不参加运算。

所以只需要把IP数据包中的前20个16进制数提取出来作为运算的数据即可。

图1 IP数据包格式(2)抓包得到的数据报图2 TCP数据报如图2,通过wireshark抓包,随机选择一个TCP数据报,根据TCP数据报的格式,我们分析数据报内容可以知道:首先开始6个字节为目的mac地址,后面6个字节为目的mac地址,后面2个字节为协议类型为0800,是IP协议包。

所以再后面的20个字节就是IP数据报的首部部分。

也就是实验所需要的数据。

IP首部为:450000280000400034060ab73baf84710a687191并且,通过包的计算的校验和结果,此包被留下,校验和的值为0。

也是座位后面对设计程序计算得到结果的一个验证。

2.设计计算首部校验和的的算法(1)程序设计的函数模块关系输入IP首部string IP0转化为二进制字符串并划分为10个字段IP1~IP10,函数Getziduan()求字段反码,函数FanMa()反码求和函数FanSum();FanSum0();求出由上一布得到的结果的反码,输出结果(2)算法流程首先将IP首部即40位16进制的字符串转化为二进制字符串,然后以每16位为一个字段,分为10个二进制字段。

解析IPV4报文和IPV6报文的checksum的算法

解析IPV4报文和IPV6报文的checksum的算法

解析IPV4报⽂和IPV6报⽂的checksum的算法校验和(checksum)算法,简单的说就是16位累加的反码运算:计算函数如下:我们在计算时是主机字节序,计算的结果封装成IP包时是⽹络字节序,注意这两者之间的区别,我们在从IP包⾥读取要转化为主机字节序,往IP包⾥存⼊时要转化为⽹络字节序在存⼊。

UINT32 Checksum(UINT32 cksum, VOID *pBuffer, UINT32 size){INT8 num = 0;UINT8 *p = (UINT8 *)pBuffer;if ((NULL == pBuffer) || (0 == size)){return cksum;}while (size > 1){cksum += ((UINT16)p[num] << 8 & 0xff00) | (UINT16)p[num + 1] & 0x00FF;2个字节累加,先取⽹络字节序低位左移8位(变成主机字节序⾼位),与(加)上 ⽹络字节序中的⾼位(主机字节序地位),即⽹络字节序要先变成主机字节序在进⾏累加,size -= 2;num += 2;}if (size > 0)如果长度为奇数{cksum += ((UINT16)p[num] << 8) & 0xFFFF;如果总的字节数为奇数,则最后⼀个字节单独相加num += 1;}while (cksum >> 16){cksum = (cksum & 0xFFFF) + (cksum >> 16);累加完毕将结果中⾼16位再加到低16位上,重复这⼀过程直到⾼16位为全0}return cksum;}注意:UINT32 cksum的类型,这⾥是4个字节的,防⽌在累加的过程中,数据溢出,(例如0xFF累加时就会内存溢出)详细的计算过程和原理如下⼀:ip头的计算:直接对头部数据进⾏累加(不包括原来的checksum值):1、ipv4包头ipHeadLen = (pIpHeader->ver_ihl & 0x0F) << 2;在ipv4头中,版本类型和头长度加在⼀起是1个字节(8位),各占4位,版本类型在前,长度在后,所以要取长度只能取低4位,pIpHeader->chksum = 0;因为不包括原来的checksum值,所以在每次计算前先把checksum的值置0,然后计算sum = Checksum(0, (VOID *)pIpHeader, ipHeadLen);对整个ip包头的累加pIpHeader->chksum = HTONS((UINT16)(~sum));结果为计算值的反码,(别忘转化为⽹络字节序)2、ipv6包头在ipv6中已经省略了checksum部分,但在后⾯的部分要有的,⽐如TCP/UDP包,别⾼兴的太早⼆、TCP/UDP报⽂的计算(举例UDP):这⾥的checksum包含两部分,⼀部分是伪头的累加,还有⼀部分是UDP包的累加(不包括原来的checksum值)伪头有分ipv4和ipv6两种,分别包含如下⼏部分,这⾥做下⽐较IPV4IPV6⽬的地址4字节(32位)16字节(128位)源地址4字节(32位)16字节(128位)协议类型1字节(8位)(Protocol)1字节(8位)(nextheader)(TCP/UDP)长度2字节(16位)2字节(16位)1、ipv4类型的:第⼀部分,伪头部分的计算:sum = 0;udpLen = sizeof(UDP_HEADER_T) + dhcpLen;UDP的长度= UDP的包头长度+ UDP的数据长度sum += udpLen;或者,下⾯也是⼀样的,这⾥就是⽹络字节序和主机字节序的区别了,上⾯的是(主机字节序)直接累加,下⾯的是⽹络字节序,⼀定要变成主机字节序后累加pUdpHeader->len = HTONS(udpLen);主机字节序转化为⽹络字节序,存⼊数据包中,⼀定要注意,我们做的所有累加也是⽹络字节序,这⾥⼀定要搞清楚,以防混淆搞错了sum += (pUdpHeader->len >> 8 & 0x00FF);2个字节的累加,先取⽹络字节序的⾼位,右移8位,变成主机字节序的低位,累加sum += (pUdpHeader->len << 8 & 0xFF00);在取⽹络字节序的低位,左移8位,变成主机字节序的⾼位,累加sum = Checksum(sum, (VOID *)&pIpHeader->saddr, 4);sum = Checksum(sum, (VOID *)&pIpHeader->daddr, 4);对4位的地址进⾏累加sum += ((UINT16)pIpHeader->proto & 0x00FF);对1位的协议类型进⾏累加伪头部分计算完成第⼆部分,UDP数据包的计算pUdpHeader->chksum = 0;注意:每次计算前别忘先把checksum的值置0,然后计算sum = Checksum(sum, (VOID *)pUdpHeader, udpLen);对整个UDP包的累加pUdpHeader->chksum = HTONS((UINT16)(~sum));结果为计算值的反码,(别忘转化为⽹络字节序)UDP数据包部分计算完成2、ipv6类型的:第⼀部分,伪头部分的计算:sum = 0;udpLen = sizeof(UDP_HEADER_T) + dhcpLen;sum += udpLen;或者pUdpHeader->len = HTONS(udpLen);sum += (pUdpHeader->len >> 8 & 0x00FF);sum += (pUdpHeader->len << 8 & 0xFF00);sum = Checksum(sum, (VOID *)&pIpHeader->saddr, 16); sum = Checksum(sum, (VOID *)&pIpHeader->daddr, 16);对16位的地址进⾏累加sum += ((UINT16)pIpHeader->proto & 0x00FF); 伪头部分计算完成第⼆部分,UDP数据包的计算pUdpHeader->chksum = 0;注意:每次计算前别忘先把checksum的值置0,然后计算sum = Checksum(sum, (VOID *)pUdpHeader, udpLen);对整个UDP包的累加pUdpHeader->chksum = HTONS((UINT16)(~sum));结果为计算值的反码,(别忘转化为⽹络字节序)UDP数据包部分计算完成。

校验和算法——精选推荐

校验和算法——精选推荐

校验和算法转⾃经常看计算机⽹络相关的书时,每次看到关于IP或者是UDP报头校验和时,都是⼀笑⽽过,以为相当简单的东西,不就是16bit数据的相加吗!最近在学习Ping命令的源待时,看到⾥⾯有关于校验和的算法。

⼀头雾⽔,后来查找资料,看到校验和是16bit字的⼆进制反码和。

总是觉得很奇怪,为什么会⽤反码和,⽽不是直接求和呢?或者是补码和呢?因为在计算机⾥⾯数据是以补码的形式存在啊!经过看书查资料,下⾯总结⼀些这个校验和算法具体是怎么实现的。

⾸先,IP、ICMP、UDP和TCP报⽂头都有检验和字段,⼤⼩都是16bit,算法基本上也是⼀样的。

在发送数据时,为了计算数据包的检验和。

应该按如下步骤:1、把校验和字段设置为0;2、把需要校验的数据看成以16位为单位的数⼦组成,依次进⾏⼆进制反码求和;3、把得到的结果存⼊校验和字段中在接收数据时,计算数据包的检验和相对简单,按如下步骤:1、把⾸部看成以16位为单位的数字组成,依次进⾏⼆进制反码求和,包括校验和字段;2、检查计算出的校验和的结果是否为0;3、如果等于0,说明被整除,校验和正确。

否则,校验和就是错误的,协议栈要抛弃这个数据包。

虽然说上⾯四种报⽂的校验和算法⼀样,但是在作⽤范围存在不同:IP校验和只校验20字节的IP报头;⽽ICMP校验和覆盖整个报⽂(ICMP报头+ICMP数据);UDP和TCP校验和不仅覆盖整个报⽂,⽽且还有12个字节的IP伪⾸部,包括源IP地址(4字节)、⽬的IP地址(4字节)、协议(2字节)、TCP/UDP包长(2字节)。

另外UDP、TCP数据报的长度可以为奇数字节,所以在计算校验和时需要在最后增加填充字节0(填充字节只是为了计算校验和,可以不被传送)。

在UDO传输协议中,校验和是可选的,当校验和字段为0时,表明该UDP报⽂未使⽤校验和,接收⽅就不需要校验和检查了!那如果UDP 校验和的计算结果是0时怎么办?书上有⼀句话:“如果校验和的计算结果为0,则存⼊的值为全1(65535),这在⼆进制反码计算中是等效的”那么校验和到底怎么计算了?1、什么是⼆进制反码求和对⼀个⽆符号的数,先求其反码,然后从低位到⾼位,按位相加,有益处则向⾼位进1(和⼀般的⼆进制法则⼀样),若最⾼位有进位,则向最低位进1.⾸先这⾥的反反码好像和以前学的有符号反码不⼀样,这⾥不分正负数,直接每个为都取反。

ip校验规则

ip校验规则

ip校验规则
【最新版】
目录
1.IP 校验规则的定义和作用
2.IP 校验规则的分类
3.IP 校验规则的具体实现方式
4.IP 校验规则的应用场景
5.IP 校验规则的优缺点分析
正文
一、IP 校验规则的定义和作用
IP 校验规则,是指在网络通信中,对数据包的源 IP 地址和目标 IP 地址进行校验的一种规则。

其主要作用是确保数据包在网络中的传输安全,防止非法的访问和攻击。

二、IP 校验规则的分类
IP 校验规则主要分为两种:一种是基于 IP 地址的校验,另一种是
基于 IP 地址和端口号的校验。

三、IP 校验规则的具体实现方式
IP 校验规则的具体实现方式主要有两种:一种是通过防火墙进行 IP 地址的过滤和校验,另一种是通过 IP 地址和端口号的校验来实现。

四、IP 校验规则的应用场景
IP 校验规则广泛应用于网络安全和访问控制等领域。

例如,在企业
内部网络中,可以通过设置 IP 校验规则,限制外部访问,保护企业内部网络的安全。

五、IP 校验规则的优缺点分析
IP 校验规则的优点在于可以有效地保护网络的安全,防止非法的访问和攻击。

ipv4校验方法

ipv4校验方法

ipv4校验方法IPv4是Internet Protocol Version 4的缩写,是目前网络上广泛使用的一种网络协议。

在IPv4中,IP地址由32位二进制数表示,分为4个8位的字段,每个字段用十进制表示,范围从0到255。

IPv4校验方法是确保数据在传输过程中没有被篡改或损坏的关键步骤。

IPv4校验方法采用的是一种称为校验和的检验机制。

校验和是一种简单但有效的数据完整性检验方法。

它通过对数据包中的每个16位字进行二进制求和,并将结果取反,得到一个16位的检验和值。

发送方计算出校验和后,将其添加到IPv4头部的校验和字段中,并在数据包发送出去之前对整个数据包进行校验和计算。

接收方收到数据包后,也会对整个数据包进行校验和计算,并将计算得到的校验和与接收到的校验和进行比较。

如果两者一致,说明数据包在传输过程中没有被篡改或损坏,可以接受;如果不一致,则说明数据包可能被篡改或损坏,需要丢弃。

IPv4校验和的计算过程如下:1. 将数据包中的每个16位字进行二进制求和,得到一个32位的结果。

2. 将32位的结果分为两个16位的部分,进行二进制求和,得到一个16位的结果。

3. 将16位的结果取反,得到最终的校验和值。

通过校验和的计算,可以确保数据在传输过程中没有被篡改或损坏。

然而,校验和并不能完全避免数据的错误或丢失。

因为校验和是在传输层进行计算的,而数据的错误或丢失可能发生在更低的网络层或更高的应用层。

此外,校验和的计算也会带来一定的计算开销,降低网络的传输效率。

除了校验和,IPv4还可以使用其他一些校验方法来增强数据的完整性和可靠性。

例如,可以使用循环冗余校验(CRC)来检测数据的错误和丢失。

CRC是一种更复杂但更可靠的校验方法,它通过对数据进行多项式除法运算,得到一个余数,将余数添加到数据包中作为校验码。

接收方在接收到数据包后,也会进行CRC运算,并将计算得到的余数与发送方发送的余数进行比较。

如果两者一致,说明数据包在传输过程中没有发生错误或丢失;如果不一致,则说明数据包可能发生了错误或丢失。

checksum计算方法

checksum计算方法

ICMP,IP,UDP,TCP报头部分都有checksum(检验和)字段。

ICMP和IP报头校验和的计算都很简单,使用RFC1071中给出的方法即可完成(如下)。

//计算校验和USHORT checksum(USHORT *buffer,int size){unsigned long cksum=0;while(size>1){cksum+=*buffer++;size-=sizeof(USHORT);}if(size){cksum+=*(UCHAR *)buffer;}//将32位数转换成16while (cksum>>16)cksum=(cksum>>16)+(cksum & 0xffff);return (USHORT) (~cksum);}UDP/TCP报头中的校验和的计算比较复杂的,要用到 UDP/TCP伪首部:先要填充伪首部各个字段,然后再将UDP/TCP报头以后(包括报头)的数据附加到伪首部的后面,再对位首部使用上述校验和计算,所得到的值才是UDP/TCP报头部分的校验和。

位首部可以用如下的结构体表示:typedef struct{ULONG sourceip; //源IP地址ULONG destip; //目的IP地址BYTE mbz; //置空(0)BYTE ptcl; //协议类型USHORT plen; //TCP/UDP数据包的长度(即从TCP/UDP报头算起到数据包结束的长度单位:字节)}Psd_Header;这个过程是一个很繁琐的过程,计算过几次后再也忍受不了做这样重复的工作,于是写了一个通用的计算函数。

这个函数使用起来我感觉非常方便:先封装好你的数据包(完整的,包括以太头),然后将数据包的首地址作为参数,调用该函数即可。

函数将帮你完成IP报头以及UDP/TCP报头部分校验和的计算。

//————————————————————————-// PacketCheckSum// 计算数据包的校验和// 参数:packet-待处理数据(将封装好的数据包的指针)//————————————————————————-void PacketCheckSum(unsigned char packet[]){Dlc_Header *pdlc_header=NULL; //以太头指针Ip_Header *pip_header=NULL; //IP头指针unsigned short attachsize=0; //传输层协议头以及附加数据的总长度pdlc_header=(Dlc_Header *)packet;//判断ethertype,如果不是IP包则不予处理if(ntohs(pdlc_header->ethertype)!=0×0800) return;pip_header=(Ip_Header *)(packet+14);//TCP包if(0×06==pip_header->proto){Tcp_Header *ptcp_header=NULL; //TCP头指针Tcp_Psd_Header *ptcp_psd_header=NULL;ptcp_header=(Tcp_Header *)(packet+14+((pip_header->ver_len)&15)*4); attachsize=ntohs(pip_header->total_len)-((pip_header->ver_len)&15)*4;ptcp_psd_header=(Tcp_Psd_Header *)malloc(attachsize+sizeof(Tcp_Psd_Header)); if(!ptcp_psd_header) return;memset(ptcp_psd_header,0,attachsize+sizeof(Tcp_Psd_Header));//填充伪TCP头ptcp_psd_header->destip=pip_header->destIP;ptcp_psd_header->sourceip=pip_header->sourceIP;ptcp_psd_header->mbz=0;ptcp_psd_header->ptcl=0×06;ptcp_psd_header->tcpl=htons(attachsize);//计算TCP校验和ptcp_header->chksum=0;memcpy((unsigned char *)ptcp_psd_header+sizeof(Tcp_Psd_Header),(unsigned char *)ptcp_header,attachsize);ptcp_header->chksum=checksum((unsigned short *)ptcp_psd_header,attachsize+sizeof(Tcp_Psd_Header));//计算ip头的校验和pip_header->checksum=0;pip_header->checksum=checksum((unsigned short *)pip_header,20);return;}//UDP包if(0×11==pip_header->proto){Udp_Header *pudp_header=NULL; //UDP头指针Udp_Psd_Header *pudp_psd_header=NULL;pudp_header=(Udp_Header *)(packet+14+((pip_header->ver_len)&15)*4); attachsize=ntohs(pip_header->total_len)-((pip_header->ver_len)&15)*4;pudp_psd_header=(Udp_Psd_Header *)malloc(attachsize+sizeof(Udp_Psd_Header)); if(!pudp_psd_header) return;memset(pudp_psd_header,0,attachsize+sizeof(Udp_Psd_Header));//填充伪UDP头pudp_psd_header->destip=pip_header->destIP;pudp_psd_header->sourceip=pip_header->sourceIP;pudp_psd_header->mbz=0;pudp_psd_header->ptcl=0×11;pudp_psd_header->udpl=htons(attachsize);//计算UDP校验和pudp_header->chksum=0;memcpy((unsigned char *)pudp_psd_header+sizeof(Udp_Psd_Header),(unsigned char *)pudp_header,attachsize);pudp_header->chksum=checksum((unsigned short *)pudp_psd_header,attachsize+sizeof(Udp_Psd_Header));//计算ip头的校验和pip_header->checksum=0;pip_header->checksum=checksum((unsigned short *)pip_header,20);return;}return;}需要几个头文件,以及库:#include <winsock2.h>#include <windows.h>#include “packet.h”#pragma comment(lib,”ws2_32.lib”)如果要自己填充IP数据报,那么计算Checksum是必不可少的一步,算法如下。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

IP数据包的校验和算法(载)2007-11-02 10:52IP数据包的头信息格式:+-------------------------------------------------+| 版本(4位) |+-------------------------------------------------+| 首部长度(4位) |+-------------------------------------------------+| 服务类型(TOS)8位|+-------------------------------------------------+| 数据包总长度(16位) |+-------------------------------------------------+| 标识ID号(16位) |+-------------------------------------------------+| 标志位(3位) |+-------------------------------------------------+| 片偏移(13位) |+-------------------------------------------------+| 生存时间(TTL)(8位) |+-------------------------------------------------+| 协议类型(8位) |+-------------------------------------------------+| 首部校验和(16位) |+-------------------------------------------------+| 源IP地址(32位) |+-------------------------------------------------+| 目的IP地址(32位) |+-------------------------------------------------+* IP选项(若有)(32位) *+-------------------------------------------------+* 数据*+-------------------------------------------------+这里要说的是首部校验和字段。

在发送数据时,为了计算数IP据报的校验和。

应该按如下步骤:(1)把IP数据报的校验和字段置为0。

(2)把首部看成以16位为单位的数字组成,依次进行二进制反码求和。

(3)把得到的结果存入校验和字段中。

在接收数据时,计算数据报的校验和相对简单,按如下步骤:(1)把首部看成以16位为单位的数字组成,依次进行二进制反码求和,包括校验和字段。

(2)检查计算出的校验和的结果是否等于零。

(3)如果等于零,说明被整除,校验是和正确。

否则,校验和就是错误的,协议栈要抛弃这个数据包。

首先,查看了Linux 2.6内核中的校验算法,使用汇编语言编写的,显然效率要高些。

代码如下:unsigned short ip_fast_csum(unsigned char * 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 ihlare modified, we must also specify them as outputs, or gccwill assume they contain their original values. */: "=r" (sum), "=r" (iph), "=r" (ihl): "1" (iph), "2" (ihl): "memory");return(sum);}在这个函数中,第一个参数显然就是IP数据报的首地址,所有算法几乎一样。

需要注意的是第二个参数,它是直接使用IP数据报头信息中的首部长度字段,不需要进行转换,因此,速度又快了(高手就是考虑的周到)。

使用方法会在下面的例子代码中给出。

第二种算法就非常普通了,是用C语言编写的。

我看了许多实现网络协议栈的代码,这个算法是最常用的了,即使变化,也无非是先取反后取和之类的。

考虑其原因,估计还是C语言的移植性更好吧。

下面是该函数的实现:unsigned short checksum(unsigned short *buf,int nword){unsigned long sum;for(sum=0;nword>0;nword--)sum += *buf++;sum = (sum>>16) + (sum&0xffff);sum += (sum>>16);return ~sum;}这里我要把我的惨痛的经历也要说一下,为了研究IP校验和的算法,我根据算法也进行了代码编写,可是结果总是有8位不一样,郁闷了好久,最后还是David L .Stevens给我了答案(不要误会,是在他的书中找到的答案,呵呵)。

那就是现在我们所用的机器设备大多数是使用二进制补码算法进行计算的。

因此,仅仅简单的累加得出的校验和并不是正确的结果。

下面就是IP数据报首部校验和算法的代码示例:#include <stdio.h>#include <stdlib.h>#include <linux/if_ether.h>#include <linux/ip.h>#include <sys/socket.h>#define ETH_P_LENGTH 65535#define ETHERNET_MAX_LEN 1500#define ETHERNET_MIN_LEN 46unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);unsigned short checksum(unsigned short *buf,int nword);//--------------------------------------------------------------------// Main function//// Do all if it can do////--------------------------------------------------------------------int main(int argc,char *argv[]){int listenfd;int nbyte;char buf[ETH_P_LENGTH];struct ethhdr *eth = NULL;struct iphdr *ip = NULL;short chk;//// Print banner//printf("\n\tSendArp v1.0 - scan IP and MAC\n");printf("\tNsfocus - \n");printf("\tby David Zhou\n");printf("\tDate : 2006/01/19\n\n");if ((listenfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {printf("Call socket() function error\n");return 1;}for (;;){if ((nbyte = recv(listenfd, buf, ETH_P_LENGTH, 0)) > 0){struct ethhdr *eth = (struct ethhdr *)buf;if(ntohs(eth->h_proto) == ETH_P_IP){ // EtherNet frame// print ip sumip = (struct iphdr *)&buf[14];printf("IP CheckSum = 0x%04X\n",ntohs(ip->check));//verify ip checksumchk = checksum((unsigned short*)ip,10);printf("Verify CheckSum = 0x%04X\n\n",ntohs(chk));//// reset check to calc self//ip->check = 0;// 2.6 kernelchk = ip_fast_csum((unsigned char *)ip,ip->ihl);printf("Calc CheckSum = 0x%04X - %d\n",ntohs(chk),ip->ihl);// coustom calcchk = checksum((unsigned short*)ip,10);printf("Calc CheckSum = 0x%04X\n\n",ntohs(chk));}}}return 0;}unsigned short checksum(unsigned short *buf,int nword){for(sum=0;nword>0;nword--)sum += *buf++;sum = (sum>>16) + (sum&0xffff);sum += (sum>>16);return ~sum;}/** This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries.** By Jorge Cwik <jorge@>, adapted for linux by* Arnt Gulbrandsen.*/unsigned short ip_fast_csum(unsigned char * 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 ihlare modified, we must also specify them as outputs, or gccwill assume they contain their original values. */: "=r" (sum), "=r" (iph), "=r" (ihl): "memory");return(sum);}一、校验和算法之前一直只知道IP校验和算法反码求和相关的,但具体细节不清楚,今天了解了下。

相关文档
最新文档