使用Asio Boost的ICMPv6的校验和计算问题

时间:2013-06-04 22:11:50

标签: boost-asio ipv6 ping icmp

我使用了ASIO文档中提供的ICMP example来创建一个简单的ping实用程序。但是,该示例仅涵盖IPv4,我很难将其与IPv6配合使用。

升级ICMP标头类以支持IPv6需要稍作更改 - ICMP和ICMPv6标头之间的唯一区别是ICMP类型的不同枚举。但是,我在计算需要包含在ICMPv6标头中的校验和时遇到问题。

对于IPv4,校验和基于ICMP头和有效负载。但是,对于IPv6,校验和应包括ICMPv6报头和有效负载之前的IPv6伪报头。 ICMPv6校验和功能需要知道IPv6头中的源和目标地址。但是,我们无法控制进入IPv6标头的内容。如何在Asio-Boost中完成?

供参考,请参阅下面的IPv4校验和计算功能。

void compute_checksum(icmp_header& header, Iterator body_begin, Iterator body_end)
{
  unsigned int sum = (header.type() << 8) + header.code()
    + header.identifier() + header.sequence_number();

  Iterator body_iter = body_begin;
  while (body_iter != body_end)
  {
    sum += (static_cast<unsigned char>(*body_iter++) << 8);
    if (body_iter != body_end)
    sum += static_cast<unsigned char>(*body_iter++);
  }

  sum = (sum >> 16) + (sum & 0xFFFF);
  sum += (sum >> 16);
  header.checksum(static_cast<unsigned short>(~sum));
}

[编辑]

如果校验和计算不正确会有什么后果?如果echo请求具有无效的校验和,目标主机是否会发送echo reply?

1 个答案:

答案 0 :(得分:1)

如果校验和不正确,典型的IPv6实现将丢弃数据包。所以,这是一个严重的问题。

如果你坚持自己制作包,你就必须这样做 完全。这包括找到源IP地址,将其放入 计算校验和之前的伪标头。我就是这样做的 在C中,通过调用connect()作为我的目标地址 (即使我使用UDP,因此它应该适用于ICMP):

     /* Get the source IP addresse chosen by the system (for verbose display, and 
     * for checksumming) */
    if (connect(sd, destination->ai_addr, destination->ai_addrlen) < 0) {
        fprintf(stderr, "Cannot connect the socket: %s\n", strerror(errno));
        abort();
    }
    source = malloc(sizeof(struct addrinfo));
    source->ai_addr = malloc(sizeof(struct sockaddr_storage));
    source_len = sizeof(struct sockaddr_storage);
    if (getsockname(sd, source->ai_addr, &source_len) < 0) {
        fprintf(stderr, "Cannot getsockname: %s\n", strerror(errno));
        abort();
    }

然后,后来:

        sockaddr6 = (struct sockaddr_in6 *) source->ai_addr;
        op6.ip.ip6_src = sockaddr6->sin6_addr;

        op6.udp.check =
            checksum6(op6.ip, op6.udp, (u_int8_t *) & message, messagesize);