The checksum calculation task for ICMPv6 using Asio Boost

I used the ICMP example provided in the ASIO documentation to create a simple ping utility. However, the example only covers IPv4, and it is difficult for me to work with IPv6.

Updating the ICMP header class to support IPv6 requires minor changes — the only difference between ICMP and the ICMPv6 header is the different enumeration of ICMP types. However, I have a problem calculating the checksum, which should be included in the ICMPv6 header.

For IPv4, the checksum is based on the ICMP header and payload. However, for IPv6, the checksum must include the IPv6 pseudo-header before the ICMPv6 header and payload. The ICMPv6 checksum function must know the source and destination address, which will be in the IPv6 header. However, we cannot control what is included in the IPv6 header. How can this be done in Asio-Boost?

For reference, you will find the IPv4 checksum calculation function below.

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

[EDIT]

What are the consequences if the checksum is not calculated correctly? Will the target host send an echo reply if the echo request has an invalid checksum?

+4
source share
1 answer

If the checksum is incorrect, a typical IPv6 implementation will output the packet. So this is a serious problem.

If you insist on developing the package yourself, you will have to do it completely. This involves finding the source IP address, a pseudo-header, before calculating the checksum. Here's how I do it in C, calling connect () for my assigned destination address (even when I use UDP, so it should work for 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(); } 

then later:

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

and

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

Source: https://habr.com/ru/post/1484520/


All Articles