实验四:IPv4分组收发实验
完整代码在最后
实验要求:
IPv4 分组的基本接收处理,能够检测出接收到的IP 在如下错误:校验和错、TTL错、版本号错、头部长度错、错误 目标地址,当存在多种错误时,其他错误类型优先于错误目标地址。
注:不要求实现IPv4协议中的选项和分片处理功能,目标地址 错误为IP分组的目的地址非本机IP地址。本机IP地址:192.168. 214.138
基本上就是处理pcap包,解析其中的ipv4头部信息,对头部信息进行检测是否有错。整体来说比较简单,处理解析pcap包部分需要一些处理,最后需要一个txt文本文件,提交到系统上进行验证。
实验过程:
解析pcap包:
pcap包结构:
PcapHeader:24个字节
PacketHeader:16个字节,里面有数据部分长度,可以用来检测数据包是否完整,获得数据帧的位置
PacketData:数据包部分
我们要解析的IPV4头部信息就在PacketData中
此处我们先跳过PcapHeader部分(24个字节),然后读取PacketHeader中存储数据包长度的部分,检测是否完整,同时可以获得数据帧的位置:
pcap_file = f"./propacket/pro{i}.pcap"
# print("Processing:", pcap_file)
with open(pcap_file, 'rb') as f:
# 跳过pcapHeader部分
f.seek(24)
packet_header = f.read(16) # 读取packetHeader部分
incl_len = struct.unpack('<I', packet_header[8:12])[0] # 解析获取数据包长度
data = f.read(incl_len) # 读取数据包内容——packetData部分
if len(data) < 14: #以太网帧头部一般有14个字节长
print("数据包太短")
continue
之后得到数据包data后,首先可以对以太网头部进行解析,其中可以获取上层(网络层)使用的协议,也可以在IPV4头部中获得协议版本。
eth_header = data[:14] # 获得以太网帧头部分
eth_type = struct.unpack("!H", eth_header[12:14])[0] # 头部14个字节中最后两个存储上层协议类型
提取和判断:
首先附上头部信息:
如果是ipv4协议开始对ipv4头部进行解析,版本号,首都长度,ttl等信息。
if eth_type == 0x0800: # 如果是IPv4数据包
ip_header_offset = 14 # IP头部在以太网数据包中的偏移量
ip_header_len = (data[ip_header_offset] & 0x0F) * 4#首部长度
if ip_header_len ==20:
print("首部长度正确")
# file.write("首部长度正确\n")
else:
print("首部长度错误")
file.write("头部长度错\n")
istrue=False
continue
if len(data) < ip_header_offset + ip_header_len:
print("ip头部有缺失")
continue
ip_header = data[ip_header_offset:ip_header_offset + ip_header_len]
ip_version = (ip_header[0])>>4#版本号
ip_ttl=ip_header[8]#寿命
dst_ip=socket.inet_ntoa(ip_header[16:20])#目的ip
下面具体说一下校验和的计算,在接收端(发送端下面会说)的时候只需要将首部20个字节,每两个字节(两个两位十六进制数合为一个四位十六进制数)加起来进行计算,如果有溢出的情况(进位),则加1到原数中,进的位抹除,如此重复,知道加完这10个数,如果是0xffff,则校验和计算正确。
# 计算校验和