2013-06-04 186 views
4

我已经使用ASIO文档中提供的ICMP example来创建一个简单的ping实用程序。但是,该示例仅涵盖IPv4,我很难使其适用于IPv6。使用Asio Boost的ICMPv6校验和计算问题

升级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)); 
} 

[编辑]

什么后果,如果校验和计算不正确?如果回显请求的校验和无效,目标主机是否会发送回应回复?

回答

0

如果校验和不正确,典型的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);