Skip to content

Commit 207a467

Browse files
Copilotithewei
andauthored
Fix ICMP ping for IPv6: use IPPROTO_ICMPV6 and ICMPv6 packet format (#807)
* Initial plan * Fix ICMP ping for IPv6: use IPPROTO_ICMPV6, ICMPv6 type codes, and handle no IP header in response Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com> * Fix ICMPv6 checksum, skip non-echo-reply packets, improve TTL display Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ithewei <26049660+ithewei@users.noreply.github.com>
1 parent e5d650c commit 207a467

2 files changed

Lines changed: 27 additions & 9 deletions

File tree

base/netinet.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ typedef struct tcphdr_s {
9898
#define ICMP_ADDRESS 17 /* Address Mask Request */
9999
#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
100100

101+
//----------------------icmpv6--------------------------------
102+
#define ICMP6_ECHO_REQUEST 128 /* ICMPv6 Echo Request */
103+
#define ICMP6_ECHO_REPLY 129 /* ICMPv6 Echo Reply */
104+
101105
// sizeof(icmphdr_t) = 8
102106
typedef struct icmphdr_s {
103107
uint8_t type; // message type

protocol/icmp.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ int ping(const char* host, int cnt) {
3535
int ret = ResolveAddr(host, &peeraddr);
3636
if (ret != 0) return ret;
3737
sockaddr_ip(&peeraddr, ip, sizeof(ip));
38-
int sockfd = socket(peeraddr.sa.sa_family, SOCK_RAW, IPPROTO_ICMP);
38+
int is_ipv6 = (peeraddr.sa.sa_family == AF_INET6);
39+
int sockfd = socket(peeraddr.sa.sa_family, SOCK_RAW, is_ipv6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
3940
if (sockfd < 0) {
4041
perror("socket");
4142
if (errno == EPERM) {
@@ -57,7 +58,7 @@ int ping(const char* host, int cnt) {
5758
goto error;
5859
}
5960

60-
icmp_req->icmp_type = ICMP_ECHO;
61+
icmp_req->icmp_type = is_ipv6 ? ICMP6_ECHO_REQUEST : ICMP_ECHO;
6162
icmp_req->icmp_code = 0;
6263
icmp_req->icmp_id = pid16;
6364
for (int i = 0; i < sendbytes - sizeof(icmphdr_t); ++i) {
@@ -68,7 +69,11 @@ int ping(const char* host, int cnt) {
6869
// NOTE: checksum
6970
icmp_req->icmp_seq = ++seq;
7071
icmp_req->icmp_cksum = 0;
71-
icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sendbytes);
72+
// NOTE: ICMPv6 checksum includes a pseudo-header and is auto-computed
73+
// by the kernel for IPPROTO_ICMPV6 raw sockets.
74+
if (!is_ipv6) {
75+
icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sendbytes);
76+
}
7277
start_hrtime = gethrtime_us();
7378
addrlen = sockaddr_len(&peeraddr);
7479
int nsend = sendto(sockfd, sendbuf, sendbytes, 0, &peeraddr.sa, addrlen);
@@ -77,8 +82,13 @@ int ping(const char* host, int cnt) {
7782
continue;
7883
}
7984
++send_cnt;
80-
addrlen = sizeof(peeraddr);
81-
int nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen);
85+
int nrecv;
86+
do {
87+
addrlen = sizeof(peeraddr);
88+
nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen);
89+
// For IPv6, raw sockets receive all ICMPv6 types (e.g. Neighbor
90+
// Discovery). Skip anything that is not an echo reply.
91+
} while (is_ipv6 && nrecv >= (int)sizeof(icmphdr_t) && ((icmp_t*)recvbuf)->icmp_type != ICMP6_ECHO_REPLY);
8292
if (nrecv < 0) {
8393
perror("recvfrom");
8494
continue;
@@ -87,11 +97,11 @@ int ping(const char* host, int cnt) {
8797
end_hrtime = gethrtime_us();
8898
// check valid
8999
bool valid = false;
90-
int iphdr_len = ipheader->ihl * 4;
100+
int iphdr_len = is_ipv6 ? 0 : ipheader->ihl * 4;
91101
int icmp_len = nrecv - iphdr_len;
92102
if (icmp_len == sendbytes) {
93-
icmp_res = (icmp_t*)(recvbuf + ipheader->ihl*4);
94-
if (icmp_res->icmp_type == ICMP_ECHOREPLY &&
103+
icmp_res = (icmp_t*)(recvbuf + iphdr_len);
104+
if (icmp_res->icmp_type == (is_ipv6 ? ICMP6_ECHO_REPLY : ICMP_ECHOREPLY) &&
95105
icmp_res->icmp_id == pid16 &&
96106
icmp_res->icmp_seq == seq) {
97107
valid = true;
@@ -105,7 +115,11 @@ int ping(const char* host, int cnt) {
105115
min_rtt = MIN(rtt, min_rtt);
106116
max_rtt = MAX(rtt, max_rtt);
107117
total_rtt += rtt;
108-
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, ipheader->ttl, rtt);
118+
if (is_ipv6) {
119+
printd("%d bytes from %s: icmp_seq=%u hlim=? time=%.1f ms\n", icmp_len, ip, seq, rtt);
120+
} else {
121+
printd("%d bytes from %s: icmp_seq=%u ttl=%u time=%.1f ms\n", icmp_len, ip, seq, ipheader->ttl, rtt);
122+
}
109123
fflush(stdout);
110124
++ok_cnt;
111125
if (cnt > 0) hv_sleep(1); // sleep a while, then agian

0 commit comments

Comments
 (0)