如何验证ICMP回显数据包的校验和?

How to validate the checksum of an ICMP echo packet?

提问人:Swagnik Dutta 提问时间:9/4/2023 最后编辑:Swagnik Dutta 更新时间:9/5/2023 访问量:92

问:

我有一个 ping 实用程序的工作实现,我将其作为业余爱好项目进行。我很难弄清楚在收到回显回复数据包时应如何验证校验和。我会解释为什么。

以下是我创建 ICMP 回显请求数据包的方法。

type ICMPHeader struct {
    Type           uint8
    Code           uint8
    Checksum       uint16
    Identifier     uint16
    SequenceNumber uint16
}

type ICMPPacket struct {
    Header *ICMPHeader
}

func (pinger *Pinger) createICMPPacket(seqNo int) (*ICMPPacket, error) {  
    packet := &ICMPPacket{  
       Header: &ICMPHeader{  
          Type:           ICMPHeaderType,  
          Code:           ICMPHeaderSubtype,  
          Checksum:       0, // initially zeroed
          Identifier:     0,  
          SequenceNumber: uint16(seqNo),  
       },  
    }  
  
    packetSerialized, err := packet.Serialize()  
    if err != nil {  
       return nil, errors.Wrapf(err, "error serializing ICMP packet")  
    }  
  
    packet.Header.Checksum = calculateChecksum(packetSerialized)  
  
    return packet, nil  
}

数据包中没有有效负载/数据部分,因为对于我发送回显请求数据包的用例,我在标头中包含所有相关字段。

ICMP 校验和是针对整个消息(包括标头和数据)计算的。但是,由于此方案中没有数据,因此仅使用标头字节作为校验和来完成计算。08 00 00 00 00 00 00 00f7 ff

因此,我最终发出的字节流的 ICMP 部分是,08 00 f7 ff 00 00 00 00

但是在 Wireshark 中,我看到一些任意 22 字节被添加为我的 ICMP 数据包字节流中的数据。这些字节似乎包含来自 IPv4 标头的一些信息。

echo request

第一个问题,这些字节是如何添加的?


继续前进,根据 RFC792 第 15 页中所写的内容,

在回显消息中接收到的数据必须在回显应答消息中返回。

我的回显应答数据包包含与数据包数据相同的 22 字节流。

enter image description here

我了解,在收到 ICMP 回显应答数据包后,校验和验证应包括将校验和字段归零,重新计算整个 ICMP 数据包(包括标头和有效负载)的校验和,然后将其与先前计算的校验和进行比较。

这就引出了我的下一组问题

  • ICMP 数据包中存在任意字节(在校验和计算期间未包含任意字节)(仅基于标头数据)是否会影响我的校验和验证逻辑?我应该考虑它们,还是应该只考虑标头数据进行验证?
  • 即使我选择忽略任意字节,仍然存在回显数据包(类型 8)和回显应答数据包(类型 0)之间的字段不同的问题。“类型”字段中的这种差异可确保校验和不匹配。我应该如何解决这个问题?Type

我没有找到任何关于如何验证 ICMP 回显回复的校验和的规则,即使实际的 ping 实现也不会打扰回显回复的 csfailed 变量。

任何帮助都是值得赞赏的。

GO 网络编程 校验和 ICMP

评论

0赞 Pascal de Kloe 9/6/2023
不应添加额外的字节。您不能只将数据包发送到 .请看一个工作示例。;-)Writenet.Conngolang.org/x/net/icmp
0赞 Swagnik Dutta 9/7/2023
> 你不能只是将数据包写入 net.Conn。为什么?我可以发送回显请求并接收回显回复,因此代码正常工作。由于这是一个学习练习,我避免使用任何包作为 icmp。
0赞 Swagnik Dutta 9/7/2023
虽然,我看了看,他们接受一个参数。看起来他们将其转换为套接字地址,并将该地址上的字节写入 .我觉得,在高层次上,它与所做的(除了套接字地址转换位)没有太大区别。它导致在同一个文件中net/icmpnet.Addrfunc (fd *FD) WriteToInet4(p []byte, sa *syscall.SockaddrInet4) (int, error)fd_unix.goconn.Writefunc (fd *FD) Write(p []byte) (int, error) {

答: 暂无答案