@@ -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