2013-06-04 224 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);