为了正确地计算 ICMP 报文的校验和 (checksum),我们需要遵循以下步骤: 1. **填充报文头部的校验和字段为 `0`**。 2. **将报文数据划分为 16 位块并求和**。 3. **如果报文长度为奇数,在末尾补零**。 4. **对总和取反,并将其结果存入校验和字段**。 以下是修改后的代码,增加了正确的 ICMP 校验和计算: ```python # 计算校验和 def calculate_checksum(data): checksum = 0 n = len(data) # 按 16 位块划分 for i in range(0, n - 1, 2): chunk = (data[i] << 8) + data[i + 1] checksum += chunk # 如果长度为奇数,补零 if n % 2 == 1: checksum += data[-1] << 8 # 将 32 位总和折叠为 16 位 checksum = (checksum >> 16) + (checksum & 0xFFFF) checksum += (checksum >> 16) # 对总和取反 return ~checksum & 0xFFFF # 构造 ICMP 报文 def construct_icmp(): # ICMP 报文头部: 类型(8), 代码(0), 校验和(0), 标识符(1), 序列号(1) icmp_header = struct.pack('!BBHHH', 8, 0, 0, 1, 1) data = b'Ping' # 计算校验和 checksum = calculate_checksum(icmp_header + data) # 填充校验和字段 icmp_header = struct.pack('!BBHHH', 8, 0, checksum, 1, 1) return icmp_header + data ``` ### 说明 - `calculate_checksum` 函数负责按 ICMP 的要求计算校验和。 - 数据部分(例如 `"Ping"`)被添加到报文头后计算校验和。 - 构造的 ICMP 报文将包含报文头和数据部分。 ### 使用方法 使用这个改进后的 `construct_icmp` 函数可以确保生成的 ICMP 报文具有正确的校验和,从而能够在网络中正常解析和传输。