参考链接
- 使用Python计算IP、TCP、UDP校验和 【推荐 (๑•̀ㅂ•́)و✧】
- 使用Python计算IP、TCP、UDP校验和
Python 计算 UDP 检验和
目录
一、前言
↶
IP 头部校验、UDP 校验与 TCP 校验方法基本一致,这里用参考链接一里面的 UDP 数据包来了解 UDP 检验和的计算。
二、分析
↶
UDP 计算检验和的方法和计算 IP 数据报首部检验和的方法相似。但不同的是:IP数据包的检验和只检验 IP 数据报的首部,但 UDP 的检验和是把首部和数据部分一起检验。
- 先得出 UDP 校验和部分
UDP 校验和部分 = 伪首部(12 字节) + UDP 首部(8 字节)+ 数据(n 个字节)
伪首部(12 字节) = 源 IP 地址(4 字节) + 目的 IP 地址(4 字节)+ 0x00(1 字节)+ 协议号(1 字节)+ UDP 长度(2 字节)
将 UDP 校验和部分拼出来后,将检验和置为 0 。将校验部分看成许多 16位的字串接起来的。若 UDP 用户数据部分不是偶数个字节,则要填充一个全 0 字节(但此字节不发送)。 - 按 二进制反码计算 出这些 16 位字的和
- 当无差错时,其结果应为全 1。否则就表明有差错出现,接收方就应该丢弃这个 UDP 数据报(也可以上交给应用层,但附上出现了差错的警告)
参考链接:
三、代码
↶
class Udp_check():
def __init__(self, IP_content):
self.IP_content = IP_content
self.IP_header_len = 20 #IP头部20字节
self.check_content = [] #UDP校验和部分
# UDP校验和部分 = UDP伪首部 + UDP内容(UDP首部 + UDP数据部分)
def add_udp_pseudo_header_content(self):
# UDP伪首部 = 源IP地址 + 目的IP地址 + 0x00 +协议字段 + UDP长度
#IP源地址为IP报文的13、14、15、16字节,即伪首部的源IP地址字段
self.check_content.append(self.IP_content[12])
self.check_content.append(self.IP_content[13])
self.check_content.append(self.IP_content[14])
self.check_content.append(self.IP_content[15])
#IP目的地址为IP报文的17、18、19、20字节,即伪首部的目的IP地址字段
self.check_content.append(self.IP_content[16])
self.check_content.append(self.IP_content[17])
self.check_content.append(self.IP_content[18])
self.check_content.append(self.IP_content[19])
#UDP伪首部的第三个字段,为0x00
self.check_content.append(0x00)
#协议类型是IP报文的第10字节,即伪首部的协议类型字段
self.check_content.append(self.IP_content[9])
#UDP数据长度是UDP报文中的第5、6字节,伪首部的长度字段
self.check_content.append(self.IP_content[self.IP_header_len + 4])
self.check_content.append(self.IP_content[self.IP_header_len + 5])
def add_udp_content(self):
#udp内容的长度
udp_content_len = len(self.IP_content) - self.IP_header_len
#往校验部分添加udp内容
for i in range(udp_content_len):
self.check_content.append(self.IP_content[self.IP_header_len + i])
def set_and_fill_zero(self):
self.check_content[18] = 0 #把原来的校验和设置为0
self.check_content[19] = 0
if len(self.check_content) % 2 == 1: #整个报文长度为奇数需要补充0
self.check_content.append(0x00)
def check_process(self):
data_sum = []
#先需要将前后二个数合并成16位长度的16进制的数
for num in range(0, len(self.check_content), 2):
#如果转换为16进制后只有1位需要高位补0操作,用zfill方法
part1 = str(hex(self.check_content[num]))[2:].zfill(2)
part2 = str(hex(self.check_content[num+1]))[2:].zfill(2)
part_all = part1 + part2
data_sum.append(int(part_all, 16))
## print(data_sum)
sum_total = sum(data_sum) #计算所有数的和
sum_total_hex = str(hex(sum_total))[2:] #16进制化
sum_total_hex_len = len(sum_total_hex) #取得字节长度
if sum_total_hex_len > 4: #求和的结果大于2个[字节16位]的话,分割成2个2字节16位数
part1 = int(sum_total_hex[: sum_total_hex_len - 4], 16) #分割第一、二字节的十六进制数字,转换为10进制
part2 = int(sum_total_hex[sum_total_hex_len - 4: ], 16) #分割第三、四字节的十六进制数字,转换为10进制
part_all = part1 + part2
else:
part_all = sum_total
last_check_sum = str(hex(65535 - part_all))[2:] #二个字节的十六进制数之和取反
return sum_total_hex, last_check_sum
def run(self):
self.add_udp_pseudo_header_content()
self.add_udp_content()
check1 = str(hex(self.check_content[18]))[2:]
check2 = str(hex(self.check_content[19]))[2:]
print("检验和:0x{0}{1}".format(check1, check2))
self.set_and_fill_zero()
print('需要计算的UDP校验和内容为:{}'.format((self.check_content)))
## UDP校验和部分准备完成
sum_total_hex, last_check_sum = self.check_process()
print("sum_total_hex: 0x{}".format(sum_total_hex))
print("检验和:0x{0}".format(last_check_sum))
temp = hex((int(sum_total_hex, 16) >> 16) + (int(s