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

1.1 ip校验和的计算

Ip校验是针对ip头部的,即仅校验ip头部,而对于ip数据部分的校验,则交由相应的四次协议来保证, ip 头部中校验和字段为16bit。

计算原理如下:

1.把校验和字段设置为0

2.计算ip头部中所有16bit的字之和

3.将2中得到的和按位取反,得到校验和。

1.2 tcp校验和的计算原理

对于ip层协议来说,其校验和只要计算ip头即可,那相对的,对于四层协议来说,其校验和则需要计算四层头部与四层数据。

tcp校验需要将ip伪首部、tcp报头、tcp数据分为16位的字,然后进行累加(如果总长度为奇数个字节,则在最后增添一个位都为0的字节 ),最后对累加的和进行按位取反即可。

Ip伪首部包括源ip地址(4字节)、目的ip地址(4字节)、协议号(两字节)、tcp包长(2字节) ,共12字节。

1.3 udp校验和的计算原理

Udp校验与tcp校验基本上是一致的。

udp校验需要将ip伪首部、udp报头、udp数据分为16位的字,然后进行累加(如果总长度为奇数个字节,则在最后增添一个位都为0的字节 ),最后对累加的和进行按位取反即可。

Ip伪首部包括源ip地址(4字节)、目的ip地址(4字节)、协议号(两字节)、tcp包长(2字节) ,共12字节。

以上就是ip、tcp、udp的校验和的计算原理,如果是我们自己写相应的校验和函数,问题也不是太大,只要根据其计算原理即可。



UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。
这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。
伪首部+UDP首部+数据 一起计算校验和。

UDP检验和的计算方法是:
1.按每16位求和得出一个32位的数;
2.如果这个32位的数,高16位不为0,则高16位加低16位再得到一个32位的数;
3.重复第2步直到高16位为0,将低16位取反,得到校验和。



upd检验和的计算类似于ip首部检验和,udp检验和是一个端到端的检验和,由发送端计算,然后由接收端验证。如果接收端检测到检验和有差 错,udp数据报就要被丢弃。 
下面我以本机接收到的一个udp数据包为例,来分析一下udp检验和的计算。 
0000: 00  e0 4c a9 28 92 00 e0 0f 7d 1e ba 08 00 45 00 
0010: 00  54 00 00 40 00 37 11 6c ea db 85 28 25 c0 a8 
0020: 12  5c 1f 40 0f a0 00 40 71 2a 02 0f  19 00 02 2e 
0030: eb 3f  34 21 51 c4 b6 cb 12 05 a3 24 b4 11 a8 d3 
0040: 93 d2 cf ac 48 b7 98 d4 83 03 1a ae 14 11 ed 24 
0050: bf c8 6f db 9a fa d8 c6 2a ca 21 08 a2 bd 25 8b 
0060: 96 03 
00 e0 4c a9 28 92 00 e0 0f 7d 1e ba 08 00----以太网帧首部(14字节) 
45 00 00 54 00 00 40 00 37 11 6c ea db 85 28 25 c0 a8 12 5c----ip首部(20字节) 
1f 40 0f a0 00 40 71 2a----udp首部(8字节);其中1f 40表示16位源端口号8000;0f a0表示16位目的端口号4000;00 40表示upd长度为64 字节;71 2a表示udp检验和(这是发送端计算出来的,一会儿在后面计算时还要使用到)。 
02 0f ………………96 03-----其余部分为udp数据部分。 
下面让我们一起来计算一下检验和。

udp数据报和tcp报文段在为了计算检验和而设置了一个12字节长的伪首部。由于udp数据报的长度可以为奇数字节,但是检验和算法是把若 干个16 bit字相加,因此可在填充字节字段填入0,可能增加的填充字节不被传送。

因此必须构造12字节的伪首部:db 85 28 25 c0 a8 12 5c 00 11 00 40 
构造完毕之后,把udp检验和部分置0,然后对udp每个16 bit进行二进制反码求和,db85+2825+c0a8+125c+0011+0040 + 1f40+0fa0+0040+0000 +……+258b+9603=e8ec7 
(0xe8ec7 >> 16) + (0xe8ec7 & 0xffff)=0x8ed5 
最后,0x8ed5+0x712a=0xffff 
由此可以判断上述udp数据报在传输过程中没有发生差错。



把十六进制的字串转为十进制数字:
Python代码
>>> print int(‘ff‘, 16)   
255


 1 #原始IP报文按照字节拆分成10进制list
 2 IP_content = [69, 0, 1, 35, 127, 30, 0, 0, 64, 17, 213, 133, 10, 8, 136, 23, 10, 8, 136, 255, 214, 131, 214, 131, 1, 15, 95, 98, 0, 115, 104, 121, 121, 121, 102, 45, 103, 117, 116, 105, 110, 103, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 95, 39, 2, 0, 0, 0, 0, 48, 180, 159, 6, 0, 0, 0, 0, 51, 39, 0, 0, 0, 0, 0, 0, 16, 95, 39, 2, 0, 0, 0, 0, 192, 4, 110, 5, 0, 0, 0, 0, 124, 106, 122, 112, 0, 0, 0, 0, 152, 163, 218, 111, 0, 0, 0, 0, 89, 184, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 151, 218, 4, 0, 0, 0, 0, 164, 180, 159, 6, 0, 0, 0, 0, 192, 180, 159, 6, 0, 0, 0, 0, 168, 217, 122, 123, 97, 99, 54, 53, 100, 102, 100, 98, 45, 54, 50, 55, 52, 45, 52, 101, 101, 52, 45, 98, 99, 100, 100, 45, 52, 53, 98, 54, 97, 98, 99, 99, 55, 49, 54, 57, 125, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 160, 180, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 165, 138, 243]
 3
 4 #原始UDP报文部分按照10进制组成list
 5 [214, 131, 214, 131, 1, 15, 95, 98, 0, 115, 104, 121, 121, 121, 102, 45, 103, 117, 116, 105, 110, 103, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 95, 39, 2, 0, 0, 0, 0, 48, 180, 159, 6, 0, 0, 0, 0, 51, 39, 0, 0, 0, 0, 0, 0, 16, 95, 39, 2, 0, 0, 0, 0, 192, 4, 110, 5, 0, 0, 0, 0, 124, 106, 122, 112, 0, 0, 0, 0, 152, 163, 218, 111, 0, 0, 0, 0, 89, 184, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 151, 218, 4, 0, 0, 0, 0, 164, 180, 159, 6, 0, 0, 0, 0, 192, 180, 159, 6, 0, 0, 0, 0, 168, 217, 122, 123, 97, 99, 54, 53, 100, 102, 100, 98, 45, 54, 50, 55, 52, 45, 52, 101, 101, 52, 45, 98, 99, 100, 100, 45, 52, 53, 98, 54, 97, 98, 99, 99, 55, 49, 54, 57, 125, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 160, 180, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 165, 138, 243]
 6
 7 #需要组装计算UDP校验和部分
 8 udp_content = []
 9
10 #IP源地址为IP报文的13、14、15、16字节
11 udp_content.append(IP_content[12])
12 udp_content.append(IP_content[13])
13 udp_content.append(IP_content[14])
14 udp_content.append(IP_content[15])
15
16 #IP目的地址为IP报文的17、18、19、20字节
17 udp_content.append(IP_content[16])
18 udp_content.append(IP_content[17])
19 udp_content.append(IP_content[18])
20 udp_content.append(IP_content[19])
21
22 #UDP数据长度是UDP报文中的第5、6字节
23 udp_content.append(IP_content[IHL + 4])
24 udp_content.append(IP_content[IHL + 5])
25
26 #协议类型是IP报文的第10字节
27 udp_content.append(0x00)
28 udp_content.append(IP_content[9])
29
30 for i in range(UDP_Len):
31     udp_content.append(IP_content[IHL + i])
32
33 udp_content[18] = 0    #把原来的校验和设置为0
34 udp_content[19] = 0
35
36 if UDP_Len % 2 == 1: #整个报文长度为奇数需要补充0
37     udp_content.append(0x00)
38
39 print(‘需要计算的UDP校验和内容为:‘ + str(udp_content))
40 manual_check = calc_checksum(udp_content)
41 print(manual_check)
42
43 #组装后的结果为,按照10进制显示
44 udp_content = [10, 8, 136, 23, 10, 8, 136, 255, 1, 15, 0, 17, 214,131, 214, 131, 1, 15, 0, 0, 0, 115, 104, 121, 121, 121, 102, 45, 103, 117, 116,105, 110, 103, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 95, 39, 2, 0, 0, 0, 0, 48, 180, 159, 6, 0, 0, 0, 0, 51, 39, 0, 0, 0, 0, 0, 0, 16, 95, 39, 2, 0, 0, 0, 0, 192, 4, 110, 5, 0, 0, 0, 0, 124, 106, 122, 112, 0, 0, 0, 0,152, 163, 218, 111, 0, 0, 0, 0, 89, 184, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112, 151, 218, 4, 0, 0, 0, 0, 164, 180, 159, 6, 0, 0, 0, 0, 192, 180, 159,6, 0, 0, 0, 0, 168, 217, 122, 123, 97, 99, 54, 53, 100, 102, 100, 98, 45, 54, 50, 55, 52, 45, 52, 101, 101, 52, 45, 98, 99, 100, 100, 45, 52, 53, 98, 54, 97, 98, 99, 99, 55, 49, 54, 57, 125, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 160, 180, 159, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 165, 138, 243, 0]
45
46 def calc_checksum(sum_data):
47     join_sum_data = []
48     for i in range(0, len(sum_data), 2):    #先需要将前后二个数合并成16位长度的16进制的数
49         first_part = str(hex(sum_data[i]))[2:]    #10进制转换为16进制,长度为8位
50         if len(first_part) < 2:    #如果转换为16进制后只有1位需要高位补0操作
51             first_part = ‘0‘ + first_part
52
53         second_part = str(hex(sum_data[i + 1]))[2:]    #10进制转换为16进制,长度为8位
54         if len(second_part) < 2:    #如果转换为16进制后只有1位需要高位补0操作
55             second_part = ‘0‘ + second_part
56
57         total_part = first_part + second_part    #合并成16位长度
58
59         join_sum_data.append(int(total_part, 16))    #重新把16进制转换为10进制
60         #join_sum_data.append(total_part)
61
62     #print(join_sum_data)
63
64     sum_result = 0
65     for single_value in join_sum_data:
66         sum_result = sum_result + single_value    #计算所有数的和
67
68     hex_sum_result = str(hex(sum_result))[2:]    #转变为4字节32位的十六进制格式
69
70     len_hex_sum = len(hex_sum_result)    #取得字节数
71
72     if len_hex_sum > 4:    #求和的结果大于2个字节16位的话,分割成二个2字节16位数
73         first_part = int(hex_sum_result[:len_hex_sum - 4], 16)    #分割第一、二字节的十六进制数字,转换为10进制
74
75         second_part = int(hex_sum_result[len_hex_sum - 4:], 16)    #分割第三、四字节的十六进制数字,转换为10进制
76
77         last_check_sum = str(hex(0xffff - (first_part + second_part)))[2:]    #二个字节的十六进制数之和取反
78         return last_check_sum
79     else:
80         last_check_sum = str(hex(65535 - sum_result))[2:]    #只有二个字节的十六进制数直接取反就好了
81         return last_check_sum
时间: 2024-08-04 16:13:37

使用Python计算IP、TCP、UDP校验和的相关文章

Socket(套接字) IP TCP UDP HTTP

Socket(套接字) (转)什么是套接字(Socket)? 应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据.为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)(socket是操作系统提供出来的接口)的接口,区分不同应用程序进程间的网络通信和连接.生成套接字,主要有3个参数:通信的目的IP地址.使用的传输 层

IP,TCP,UDP Checksum校验

IP数据报的校验: IP数据报只需要对数据头进行校验,步骤如下: 将接收到的数据的checksum字段设置为0 把需要校验的字段的所有位划分为16位(2字节)的字 把所有16位的字相加,如果遇到进位,则将高于16字节的进位部分的值加到最低位上,举例,0xBB5E+0xFCED=0x1 B84B,则将1放到最低位,得到结果是0xB84C 将所有字相加得到的结果应该为一个16位的数,将该数取反则可以得到检验和checksum. 上述第2步中也可以不用每次把进位加到低位,可以等所有数据计算结束再将高位

以太网,IP,TCP,UDP数据包分析

http://www.cnblogs.com/feitian629/archive/2012/11/16/2774065.html 1.ISO开放系统有以下几层: 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 2.TCP/IP 网络协议栈分为应用层(Application).传输层(Transport).网络层(Network)和链路层(Link)四层. 通信过程中,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如

python学习之TCP/UDP

TCP/UDP都是网络编程(socket)的两种基于C/S结构的程序. UDP:非可靠连接速度快,服务器:创建socket 绑定ip和端口后直接从指定的IP和端口接收数据不用侦听:客户端:创建socket ,直接接收数据,不需要建立连接. s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 绑定端口: s.bind(('127.0.0.1', 9999)) s.recvfrom(1024) #接收数据. TCP:可靠连接,客户端此外还需要

python 网络通信协议/TCP,UDP区别

一.osi七层协议 互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层 协议具体内容 各层的功能简述: [1]物理层:主要定义物理设备标准,如网线的接口类型.光纤的接口类型.各种传输介质的传输速率等.它的主要作用是传输比特流(就是由1.0转化为电流强弱来进行传输,到达目的地后在转化为1.0,也就是我们常说的数模转换与模数转换),这一层的数据叫做比特. [2]数据链路层:定义了如何让格式化数据以进行传输,以及如何让控制对物理介质的访问,这一层通常还提供错误检测和纠正,以确保数

TCP/IP、UDP、Http、Socket的区别

一.网络七层模型 20世纪70年代中,为了优化数据库系统设计,支持数据库系统的访问,美国的一个互联网研究小组提出了一个结构化的分布式通信系统体系结构(共七层),他们内部称之为分布式系统体系结构(DSA),1977年英国标准化协会向国际标准化组织(ISO)提议,为了定义分布处理之间的通信基础设施,需要一个标准的体系结构.后来,ISO就开放系统互联(OSI)问题成立了一个专委会(TC 97, Subcomittee 16),指定由美国国家标准协会(ANSI)开发一个标准草案.1978年3月,在ISO

笔记 传输层TCP/UDP

OSI 7 层 1 - 物理层 2 - 数据链路层 3 - 网络层 编址和路由 4 - 传输层 提供端到端的数据连接(端,就是端口的端) TCP UDP 5 - 会话层(系统内部实现机制,数据包中无法体现出来) 6 - 表示层(系统内部实现机制,数据包中无法体现出来) 7 - 应用层 ================================================== seq: sequence number , 序列号: acknowledge :确定号: mask : 掩码:

python编程系列---tcp服务端的简单实现

流程如下: """tcp服务端创建流程1. 创建服务端的tcp socket : server_socket 用于监听客户端的请求2. 绑定端口3. server_socket开启监听,由主动连接模式变为被动接受模式4. 等待接收客户端的请求, 一有连接,则立即响应,且创建一个与客户端对接的socket,用该socket与客户端通信5. 使用新创建的socket与客户端通信6. 关闭新创建的socket, 该socket关闭,则与当前客户端结束通信7. server_sock

python实现TCP/UDP通信

一.说明 对于TCP/udp的说明已经很多了,我在这里只是简单的说明一下 二.套接字scoket 套接字是一种具有之前所说的"通信端点"概念的计算网络数据结构.相当 于电话插口,没它无法通信,这个比喻非常形象.        套接字起源于20世纪70年代加州伯克利分校版本的Unix,即BSD Unix .又称为"伯克利套接字"或"BSD套接字".最初套接字被设计用在同一台 主机上多个应用程序之间的通讯,这被称为进程间通讯或IPC.