【问题标题】:C++ - Access violation when constructing ICMP packetC++ - 构造 ICMP 数据包时的访问冲突
【发布时间】:2013-08-14 21:31:21
【问题描述】:

我正在使用 ping 工具,当使用 45041 或更大的数据包大小(包括 ICMP 标头)时,我在计算 ICMP 校验和时始终在发送缓冲区周围出现访问冲突。任何大小为 45040 或以下的数据包都不会引发错误,并以正确的校验和正确传输。缩写代码如下;在第一次迭代的校验和函数中取消引用 while 循环内的缓冲区时会发生访问冲突。

typedef struct ICMPHeader 
{
  BYTE type;          // ICMP packet type
  BYTE code;          // Type sub code
  USHORT checksum;
  USHORT id;
  USHORT seq;
} ICMPHeader;

typedef struct echoRequest
{
  ICMPHeader icmpHead;
  char *data;
} EchoRequest;

// ...
EchoRequest *sendBuffer = new EchoRequest();
sendBuffer->data = new char[packetSize];

memset((void *)sendBuffer->data, 0xfa, packetSize);

sendBuffer->icmpHead.checksum = ipChecksum((USHORT *)sendBuffer, 
                                     packetSize + sizeof(sendBuffer->icmpHead));
// ...

// checksum function
USHORT ipChecksum(USHORT *buffer, unsigned long size)
{
  unsigned long cksum = 0;

  while (size > 1) 
  {
    cksum += *buffer++;
    size -= sizeof(USHORT);
  }

  if (size)
    cksum += *(UCHAR *)buffer;

  cksum = (cksum >> 16) + (cksum & 0xffff);
  cksum += (cksum >> 16);

  return (USHORT)(~cksum);
}

关于为什么会发生这种情况的任何想法?

确切的错误措辞:Unhandled exception at 0x009C2582 in PingProject.exe: 0xC0000005: Access violation reading location 0x004D5000.

将 Visual Studio Professional 2012 与适用于 .NET 4.0 的平台工具集 v100 结合使用

【问题讨论】:

    标签: c++ runtime-error access-violation checksum icmp


    【解决方案1】:

    您的ipChecksum 函数需要一个指向它应该校验和的数据的指针,而不是一个指向包含指向校验和数据的指针的结构的指针。所以首先它校验和icmpHead,这很好。但随后它校验和指向data 的指针,这是没有意义的。然后它在EchoRequest 结构的末尾校验和。

    【讨论】:

    • 我将EchoRequest 更改为icmpHeader,并为其之外的数据部分分配了足够的空间,它现在适用于任何大小的数据包。谢谢! (尽管我仍然不明白为什么它仍然适用于小于该阈值的数据包)。
    • @MikeBogochow 它之所以有效,是因为内存保护适用于整个页面。只要您没有跑出分配页面的末尾,它就不会崩溃,尽管它也不会生成正确的校验和。
    • 但是根据 wireshark 的校验和是正确的,我收到了我正在 ping 的主机的回复,当校验和不正确时我不是这样
    • @MikeBogochow 那么你手上有一个真正的谜。
    【解决方案2】:

    如果您希望读者将此代码解释为c++,您需要修复一些问题。

    • memset 真的吗?

    • 使用reinterpret_cast 将一种指针类型转换为另一种。

    • 通常认为使用size_t 而不是unsigned long 会更好

    • 改用smart pointers

    • 使用static_cast 将ulong 转换为ushort。

    • USHORT保证为 16 位。请改用其他类型。

    编辑:您比 MTUwaaaay。将数据包保持在 1k 字节以下。 IEEE 802.3 预计为 1492,但该值可能会有所不同。

    【讨论】:

    • 该项目开始使用纯 C,但当我遇到一些问题时我更改了 C++,我猜这部分仍然主要是 C,所以我为此道歉。感谢您的提示!
    • 对于 MTU,我的应用程序不关心数据包是否碎片化,它也可能通过以太网以外的其他东西发送,所以我只是确保它在 ICMP 定义的范围内
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-15
    • 2016-02-08
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多