本文目录导读:
这是一个关于用Python实现网络校验和计算的实用案例,包含IPv4头部校验和与TCP/UDP校验和两种常见场景。
IPv4头部校验和计算
def calculate_ip_checksum(header):
"""
计算IPv4头部校验和
参数: header - bytes类型,IP头部数据(20字节)
返回: int类型,校验和值
"""
# 将校验和字段置零
header_list = list(header)
# 第10-11字节是校验和字段(0-indexed)
header_list[10] = 0
header_list[11] = 0
# 按16位分组求和
checksum = 0
for i in range(0, len(header_list), 2):
word = (header_list[i] << 8) + header_list[i+1]
checksum += word
# 处理进位
while checksum > 0xFFFF:
checksum = (checksum & 0xFFFF) + (checksum >> 16)
# 取反得到校验和
checksum = ~checksum & 0xFFFF
return checksum
# 示例:计算IP头部校验和
def test_ip_checksum():
# 构建一个示例IP头部(不含校验和)
# 版本4,头部长度5(20字节),服务类型0,总长度20
# 标识12345,标志和偏移0,TTL64,协议TCP(6),源地址192.168.1.1,目的地址192.168.1.2
ip_header = bytes([
0x45, 0x00, # 版本和头部长度,服务类型
0x00, 0x14, # 总长度20
0x30, 0x39, # 标识12345
0x40, 0x00, # 标志和偏移
0x40, 0x06, # TTL64,协议TCP
0x00, 0x00, # 校验和(待计算)
0xC0, 0xA8, 0x01, 0x01, # 源地址192.168.1.1
0xC0, 0xA8, 0x01, 0x02 # 目的地址192.168.1.2
])
checksum = calculate_ip_checksum(ip_header)
print(f"IPv4头部校验和: 0x{checksum:04X}")
# 验证:将计算出的校验和放回头部,重新计算应该为0
ip_header_with_checksum = bytearray(ip_header)
ip_header_with_checksum[10] = (checksum >> 8) & 0xFF
ip_header_with_checksum[11] = checksum & 0xFF
verify_sum = calculate_ip_checksum(bytes(ip_header_with_checksum))
print(f"验证结果(应为0): 0x{verify_sum:04X}")
if __name__ == "__main__":
test_ip_checksum()
TCP/UDP校验和计算(包含伪头部)
import struct
def calculate_tcp_checksum(ip_src, ip_dst, tcp_segment):
"""
计算TCP校验和
参数:
ip_src - 源IP地址字符串,如"192.168.1.1"
ip_dst - 目的IP地址字符串
tcp_segment - bytes类型,TCP段数据(包含TCP头部和数据)
返回: int类型,校验和值
"""
# 解析IP地址
src_bytes = bytes(map(int, ip_src.split('.')))
dst_bytes = bytes(map(int, ip_dst.split('.')))
# 构建伪头部 (12字节)
pseudo_header = struct.pack('!4s4sBBH',
src_bytes,
dst_bytes,
0, # 保留
6, # TCP协议号
len(tcp_segment) # TCP段长度
)
# 组合伪头部和TCP段进行校验和计算
data = pseudo_header + tcp_segment
# 如果数据长度为奇数,补一个0字节
if len(data) % 2 != 0:
data += b'\x00'
# 计算校验和
checksum = 0
for i in range(0, len(data), 2):
word = (data[i] << 8) + data[i+1]
checksum += word
# 处理进位
while checksum > 0xFFFF:
checksum = (checksum & 0xFFFF) + (checksum >> 16)
# 取反
checksum = ~checksum & 0xFFFF
return checksum
# UDP校验和类似,只是协议号不同
def calculate_udp_checksum(ip_src, ip_dst, udp_datagram):
"""
计算UDP校验和
参数:
ip_src - 源IP地址字符串
ip_dst - 目的IP地址字符串
udp_datagram - bytes类型,UDP数据报(包含UDP头部和数据)
返回: int类型,校验和值
"""
src_bytes = bytes(map(int, ip_src.split('.')))
dst_bytes = bytes(map(int, ip_dst.split('.')))
# UDP伪头部 (协议号17)
pseudo_header = struct.pack('!4s4sBBH',
src_bytes,
dst_bytes,
0, # 保留
17, # UDP协议号
len(udp_datagram)
)
data = pseudo_header + udp_datagram
if len(data) % 2 != 0:
data += b'\x00'
checksum = 0
for i in range(0, len(data), 2):
word = (data[i] << 8) + data[i+1]
checksum += word
while checksum > 0xFFFF:
checksum = (checksum & 0xFFFF) + (checksum >> 16)
checksum = ~checksum & 0xFFFF
return checksum
# 测试示例
def test_tcp_checksum():
# 构建一个简单TCP段(假设来自HTTP请求)
# 源端口12345,目的端口80,序列号1000,确认号2000
# 头部长度5(20字节),标志SYN(0x02),窗口大小65535
tcp_header = struct.pack('!HHLLBBHHH',
12345, # 源端口
80, # 目的端口
1000, # 序列号
2000, # 确认号
0x50, # 数据偏移(5*4=20字节)
0x02, # 标志位 (SYN)
65535, # 窗口大小
0, # 校验和(待计算)
0 # 紧急指针
)
# TCP数据(可选,这里为空)
tcp_data = b''
tcp_segment = tcp_header + tcp_data
# 将校验和字段置零(第16-17字节)
tcp_segment_list = bytearray(tcp_segment)
tcp_segment_list[16] = 0
tcp_segment_list[17] = 0
tcp_segment = bytes(tcp_segment_list)
checksum = calculate_tcp_checksum(
"192.168.1.1",
"192.168.1.2",
tcp_segment
)
print(f"TCP校验和: 0x{checksum:04X}")
def test_udp_checksum():
# 构建一个简单UDP数据报
# 源端口12345,目的端口53(DNS),长度8(头部)+ 数据
udp_data = b'Hello World'
udp_length = 8 + len(udp_data) # UDP头部8字节
udp_header = struct.pack('!HHHH',
12345, # 源端口
53, # 目的端口
udp_length, # 长度
0 # 校验和(待计算)
)
udp_datagram = udp_header + udp_data
# 将校验和字段置零(第6-7字节)
udp_list = bytearray(udp_datagram)
udp_list[6] = 0
udp_list[7] = 0
udp_datagram = bytes(udp_list)
checksum = calculate_udp_checksum(
"192.168.1.1",
"192.168.1.2",
udp_datagram
)
print(f"UDP校验和: 0x{checksum:04X}")
if __name__ == "__main__":
print("=== TCP校验和测试 ===")
test_tcp_checksum()
print("\n=== UDP校验和测试 ===")
test_udp_checksum()
校验和验证函数
def verify_checksum(data, checksum_type='ip'):
"""
验证校验和是否正确
参数:
data - bytes类型,包含校验和字段的完整数据
checksum_type - 'ip', 'tcp', 或 'udp'
返回: bool,校验和是否正确
"""
if checksum_type == 'ip':
# IP头部校验和验证:整个头部重新计算应为0
calc_sum = calculate_ip_checksum(data)
return calc_sum == 0
else:
# TCP/UDP需要提供源和目的IP(这里简化仅做示例)
raise ValueError("TCP/UDP验证需要额外的IP地址信息")
# 使用示例
if __name__ == "__main__":
print("\n=== 通用校验和验证示例 ===")
# 构建正确的IP头部
ip_header = bytes([
0x45, 0x00, 0x00, 0x14,
0x30, 0x39, 0x40, 0x00,
0x40, 0x06, 0x00, 0x00, # 校验和先置0
0xC0, 0xA8, 0x01, 0x01,
0xC0, 0xA8, 0x01, 0x02
])
# 计算并设置校验和
checksum = calculate_ip_checksum(ip_header)
ip_header_with_csum = bytearray(ip_header)
ip_header_with_csum[10] = (checksum >> 8) & 0xFF
ip_header_with_csum[11] = checksum & 0xFF
# 验证
result = verify_checksum(bytes(ip_header_with_csum), 'ip')
print(f"校验和验证结果: {'正确' if result else '错误'}")
这个案例演示了:
- IPv4头部校验和 - 简单直接的16位累加和取反
- TCP/UDP校验和 - 包含伪头部(源IP、目的IP、协议号、段长度)
- 校验和验证 - 验证计算是否正确
实际应用中,这些函数可以用于网络抓包分析、协议实现验证、数据完整性检查等场景。
标签: 校验和