Skip to content

Fix ICMP ping for IPv6: use IPPROTO_ICMPV6 and ICMPv6 packet format#807

Merged
ithewei merged 3 commits intomasterfrom
copilot/fix-icmp-issue-ipv6
Mar 10, 2026
Merged

Fix ICMP ping for IPv6: use IPPROTO_ICMPV6 and ICMPv6 packet format#807
ithewei merged 3 commits intomasterfrom
copilot/fix-icmp-issue-ipv6

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 9, 2026

IPv6 ping fails because the socket is created with IPPROTO_ICMP regardless of address family, and the packet format assumes IPv4 throughout. recvfrom times out (errno 11 on Linux, 10060 on Windows) since the kernel never delivers ICMPv4 packets to an IPv6 socket.

Changes

  • Socket protocol: Use IPPROTO_ICMPV6 when target is AF_INET6
  • ICMPv6 type codes: Added ICMP6_ECHO_REQUEST (128) and ICMP6_ECHO_REPLY (129) constants; use them for IPv6 instead of ICMP_ECHO (8) / ICMP_ECHOREPLY (0)
  • ICMPv6 checksum: Skip self-computed checksum for IPv6 — ICMPv6 uses a pseudo-header-based checksum that is auto-computed by the kernel for IPPROTO_ICMPV6 raw sockets
  • Non-echo packet filtering: Add a receive loop to skip non-echo-reply ICMPv6 packets (Neighbor Discovery, Router Advertisements, etc.) that raw ICMPv6 sockets also receive
  • Response parsing: IPv6 raw sockets don't prepend an IP header to received data, so skip the iphdr offset for IPv6
  • Hop limit display: Print hlim=? for IPv6 instead of misleading ttl=0, since the hop limit is not available from the receive buffer without recvmsg/IPV6_RECVHOPLIMIT
int is_ipv6 = (peeraddr.sa.sa_family == AF_INET6);
int sockfd = socket(peeraddr.sa.sa_family, SOCK_RAW,
                    is_ipv6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
// ...
icmp_req->icmp_type = is_ipv6 ? ICMP6_ECHO_REQUEST : ICMP_ECHO;
// ...
icmp_req->icmp_cksum = 0;
if (!is_ipv6) {
    icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sendbytes);
}
// ...
int iphdr_len = is_ipv6 ? 0 : ipheader->ihl * 4;
Original prompt

This section details on the original issue you should resolve

<issue_title>protocol/icmp在IPv6下recvfrom返回错误</issue_title>
<issue_description>protocol/icmp在IPv6下无法使用, sendto调用正常返回,windows下recvfrom时错误代码10060, linux下错误代码 11</issue_description>

Comments on the Issue (you are @copilot in this section)

@ithewei 通过so_rcvtimeo设置了接收超时的,windows 10060和linux 11错误码都是超时未收到响应导致的,这个是正常现象 @ithewei 我发现有个socket选项可能没用适配ipv6,把IPPROTO_ICMP改成IPPROTO_ICMPV6试试呢 @ithewei 应该是ICMPV6和ICMP的报文内容也不同,需要详细研究下

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

…ndle no IP header in response

Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix ICMP issue with recvfrom in IPv6 Fix ICMP ping for IPv6: use IPPROTO_ICMPV6 and ICMPv6 packet format Mar 9, 2026
@ithewei ithewei requested a review from Copilot March 10, 2026 12:23
@ithewei ithewei marked this pull request as ready for review March 10, 2026 12:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to fix protocol/icmp “ping” behavior for IPv6 targets by using the correct socket protocol and adapting ICMP parsing/printing to IPv6 raw-socket behavior.

Changes:

  • Use IPPROTO_ICMPV6 when the resolved peer address is AF_INET6.
  • Use ICMPv6 echo request/reply type values (128/129) for IPv6.
  • Adjust receive parsing and debug output to account for IPv6 raw sockets not including an IPv4 header in the buffer.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
protocol/icmp.c Switch protocol/type codes based on address family; adjust receive offset and TTL display for IPv6.
base/netinet.h Add ICMPv6 echo request/reply type constants used by the ping implementation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread protocol/icmp.c
Comment on lines +61 to 64
icmp_req->icmp_type = is_ipv6 ? ICMP6_ECHO_REQUEST : ICMP_ECHO;
icmp_req->icmp_code = 0;
icmp_req->icmp_id = pid16;
for (int i = 0; i < sendbytes - sizeof(icmphdr_t); ++i) {
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switching to ICMPv6 type codes/protocol also requires updating the checksum logic: ICMPv6 uses an IPv6 pseudo-header in the checksum calculation (src/dst, payload length, next-header=58), but this function still computes icmp_cksum using the IPv4-style checksum over the ICMP message only. That can still result in IPv6 Echo Requests being dropped (no reply) even after changing the socket protocol/type.

Please either compute the correct ICMPv6 checksum (after determining the selected IPv6 source address, e.g. via connect() + getsockname()), or (where supported) delegate checksum generation to the kernel via setsockopt(IPPROTO_IPV6, IPV6_CHECKSUM, ...) and leave icmp_cksum as 0 for IPv6.

Copilot uses AI. Check for mistakes.
Comment thread protocol/icmp.c Outdated
max_rtt = MAX(rtt, max_rtt);
total_rtt += rtt;
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, ipheader->ttl, rtt);
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, is_ipv6 ? 0 : ipheader->ttl, rtt);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For IPv6 replies this prints ttl=0, which is a misleading value (and IPv6 uses Hop Limit rather than TTL). Consider either omitting this field for IPv6, printing a sentinel like ttl=?/hlim=?, or retrieving the hop limit via recvmsg + IPV6_RECVHOPLIMIT/IPV6_HOPLIMIT and printing the actual value.

Suggested change
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, is_ipv6 ? 0 : ipheader->ttl, rtt);
if (is_ipv6) {
// IPv6 uses Hop Limit instead of TTL; we are not retrieving the actual hop limit here,
// so print a sentinel instead of a misleading numeric value.
printd("%d bytes from %s: icmp_seq=%u hlim=? time=%.1f ms\n", icmp_len, ip, seq, rtt);
} else {
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, ipheader->ttl, rtt);
}

Copilot uses AI. Check for mistakes.
@ithewei
Copy link
Copy Markdown
Owner

ithewei commented Mar 10, 2026

@copilot apply changes based on the comments in this thread

Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 10, 2026

@copilot apply changes based on the comments in this thread

Applied both suggestions in 4cf5a47:

  • ICMPv6 checksum is now left as 0 for the kernel to auto-compute (since ICMPv6 uses a pseudo-header checksum).
  • IPv6 output now prints hlim=? instead of the misleading ttl=0.

@ithewei ithewei merged commit 207a467 into master Mar 10, 2026
12 checks passed
@ithewei ithewei deleted the copilot/fix-icmp-issue-ipv6 branch March 17, 2026 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

protocol/icmp在IPv6下recvfrom返回错误

3 participants