From 7cbe42f95531351a65701f535d26908fadba89e1 Mon Sep 17 00:00:00 2001 From: ningss Date: Tue, 8 Apr 2025 13:57:38 +0800 Subject: [PATCH 1/3] fix: icmp ipv6 --- base/netinet.h | 5 ++ examples/CMakeLists.txt | 5 ++ examples/ping.c | 15 ++++++ hconfig.h | 102 ---------------------------------------- protocol/icmp.c | 71 ++++++++++++++++++---------- 5 files changed, 72 insertions(+), 126 deletions(-) create mode 100644 examples/ping.c delete mode 100644 hconfig.h diff --git a/base/netinet.h b/base/netinet.h index 4969639e9..06b1cfac2 100644 --- a/base/netinet.h +++ b/base/netinet.h @@ -98,6 +98,11 @@ typedef struct tcphdr_s { #define ICMP_ADDRESS 17 /* Address Mask Request */ #define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ +#define ICMPV6_DEST_UNREACH 1 +#define ICMPV6_TIME_EXCEEDED 3 +#define ICMPV6_ECHO 128 +#define ICMPV6_ECHOREPLY 129 + // sizeof(icmphdr_t) = 8 typedef struct icmphdr_s { uint8_t type; // message type diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a216514e8..fbd76604d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -178,4 +178,9 @@ if(WITH_MQTT) list(APPEND EXAMPLES mqtt_sub mqtt_pub mqtt_client_test) endif() +include_directories(../protocol) +add_executable(ping ping.c ../protocol/icmp.c) +target_compile_definitions(ping PRIVATE PRINT_DEBUG) +target_link_libraries(ping ${HV_LIBRARIES}) + add_custom_target(examples DEPENDS ${EXAMPLES}) diff --git a/examples/ping.c b/examples/ping.c new file mode 100644 index 000000000..23a1b7f7e --- /dev/null +++ b/examples/ping.c @@ -0,0 +1,15 @@ +#include + +#ifndef PRINT_DEBUG +#define PRINT_DEBUG +#endif + +#include "icmp.h" + +int main(int argc, char const *argv[]) { + if(argc > 1) + ping(argv[1], 4); + else + fprintf(stderr, "usage: ping \n"); + return 0; +} diff --git a/hconfig.h b/hconfig.h deleted file mode 100644 index 03d4ef2f1..000000000 --- a/hconfig.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef HV_CONFIG_H_ -#define HV_CONFIG_H_ - -#ifndef HAVE_STDBOOL_H -#define HAVE_STDBOOL_H 1 -#endif - -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H 1 -#endif - -#ifndef HAVE_STDATOMIC_H -#define HAVE_STDATOMIC_H 0 -#endif - -#ifndef HAVE_SYS_TYPES_H -#define HAVE_SYS_TYPES_H 1 -#endif - -#ifndef HAVE_SYS_STAT_H -#define HAVE_SYS_STAT_H 1 -#endif - -#ifndef HAVE_SYS_TIME_H -#define HAVE_SYS_TIME_H 1 -#endif - -#ifndef HAVE_FCNTL_H -#define HAVE_FCNTL_H 1 -#endif - -#ifndef HAVE_PTHREAD_H -#define HAVE_PTHREAD_H 1 -#endif - -#ifndef HAVE_ENDIAN_H -#define HAVE_ENDIAN_H 1 -#endif - -#ifndef HAVE_SYS_ENDIAN_H -#define HAVE_SYS_ENDIAN_H 0 -#endif - -#ifndef HAVE_GETTID -#define HAVE_GETTID 0 -#endif - -#ifndef HAVE_STRLCPY -#define HAVE_STRLCPY 1 -#endif - -#ifndef HAVE_STRLCAT -#define HAVE_STRLCAT 1 -#endif - -#ifndef HAVE_CLOCK_GETTIME -#define HAVE_CLOCK_GETTIME 1 -#endif - -#ifndef HAVE_GETTIMEOFDAY -#define HAVE_GETTIMEOFDAY 1 -#endif - -#ifndef HAVE_PTHREAD_SPIN_LOCK -#define HAVE_PTHREAD_SPIN_LOCK 0 -#endif - -#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK -#define HAVE_PTHREAD_MUTEX_TIMEDLOCK 0 -#endif - -#ifndef HAVE_SEM_TIMEDWAIT -#define HAVE_SEM_TIMEDWAIT 0 -#endif - -#ifndef HAVE_PIPE -#define HAVE_PIPE 1 -#endif - -#ifndef HAVE_SOCKETPAIR -#define HAVE_SOCKETPAIR 1 -#endif - -#ifndef HAVE_EVENTFD -#define HAVE_EVENTFD 1 -#endif - -#ifndef HAVE_SETPROCTITLE -#define HAVE_SETPROCTITLE 0 -#endif - -/* #undef WITH_OPENSSL */ -/* #undef WITH_GNUTLS */ -/* #undef WITH_MBEDTLS */ - -/* #undef ENABLE_UDS */ -/* #undef USE_MULTIMAP */ - -#define WITH_WEPOLL 1 -/* #undef WITH_KCP */ - -#endif // HV_CONFIG_H_ diff --git a/protocol/icmp.c b/protocol/icmp.c index 864a83908..ade5ee46d 100644 --- a/protocol/icmp.c +++ b/protocol/icmp.c @@ -5,8 +5,8 @@ #include "hsocket.h" #include "htime.h" -#define PING_TIMEOUT 1000 // ms -int ping(const char* host, int cnt) { +#define PING_TIMEOUT 1000 // ms +int ping(const char *host, int cnt) { static uint16_t seq = 0; uint16_t pid16 = (uint16_t)getpid(); char ip[64] = {0}; @@ -14,11 +14,11 @@ int ping(const char* host, int cnt) { uint64_t start_hrtime, end_hrtime; int timeout = 0; int sendbytes = 64; - char sendbuf[64]; - char recvbuf[128]; // iphdr + icmp = 84 at least - icmp_t* icmp_req = (icmp_t*)sendbuf; - iphdr_t* ipheader = (iphdr_t*)recvbuf; - icmp_t* icmp_res; + char sendbuf[64] = {0}; + char recvbuf[256]; // iphdr + icmp = 84 at least + icmp_t *icmp_req = (icmp_t *)sendbuf; + iphdr_t *ipheader = (iphdr_t *)recvbuf; + icmp_t *icmp_res; // ping stat int send_cnt = 0; int recv_cnt = 0; @@ -26,17 +26,22 @@ int ping(const char* host, int cnt) { float rtt, min_rtt, max_rtt, total_rtt; rtt = max_rtt = total_rtt = 0.0f; min_rtt = 1000000.0f; - //min_rtt = MIN(rtt, min_rtt); - //max_rtt = MAX(rtt, max_rtt); - // gethostbyname -> socket -> setsockopt -> sendto -> recvfrom -> closesocket + // min_rtt = MIN(rtt, min_rtt); + // max_rtt = MAX(rtt, max_rtt); + // gethostbyname -> socket -> setsockopt -> sendto -> recvfrom -> closesocket sockaddr_u peeraddr; socklen_t addrlen = sizeof(peeraddr); memset(&peeraddr, 0, addrlen); int ret = ResolveAddr(host, &peeraddr); if (ret != 0) return ret; sockaddr_ip(&peeraddr, ip, sizeof(ip)); - int sockfd = socket(peeraddr.sa.sa_family, SOCK_RAW, IPPROTO_ICMP); - if (sockfd < 0) { + const bool addr_ipv6 = (peeraddr.sa.sa_family == AF_INET6); + int sockfd = socket(peeraddr.sa.sa_family, SOCK_RAW, addr_ipv6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP); +#ifdef _WIN32 + if (sockfd == INVALID_SOCKET) { +#else + if (sockfd <= 0) { +#endif perror("socket"); if (errno == EPERM) { fprintf(stderr, "please use root or sudo to create a raw socket.\n"); @@ -44,6 +49,12 @@ int ping(const char* host, int cnt) { return -socket_errno(); } + ret = blocking(sockfd); + if (ret < 0) { + perror("ioctlsocket blocking"); + goto error; + } + timeout = PING_TIMEOUT; ret = so_sndtimeo(sockfd, timeout); if (ret < 0) { @@ -57,7 +68,7 @@ int ping(const char* host, int cnt) { goto error; } - icmp_req->icmp_type = ICMP_ECHO; + icmp_req->icmp_type = addr_ipv6 ? ICMPV6_ECHO : ICMP_ECHO; icmp_req->icmp_code = 0; icmp_req->icmp_id = pid16; for (int i = 0; i < sendbytes - sizeof(icmphdr_t); ++i) { @@ -68,7 +79,9 @@ int ping(const char* host, int cnt) { // NOTE: checksum icmp_req->icmp_seq = ++seq; icmp_req->icmp_cksum = 0; - icmp_req->icmp_cksum = checksum((uint8_t*)icmp_req, sendbytes); + // ICMP IPv6不传校验码 + if (!addr_ipv6) + icmp_req->icmp_cksum = checksum((uint8_t *)icmp_req, sendbytes); start_hrtime = gethrtime_us(); addrlen = sockaddr_len(&peeraddr); int nsend = sendto(sockfd, sendbuf, sendbytes, 0, &peeraddr.sa, addrlen); @@ -87,25 +100,35 @@ int ping(const char* host, int cnt) { end_hrtime = gethrtime_us(); // check valid bool valid = false; - int iphdr_len = ipheader->ihl * 4; + // IPv6的ICMP包不含IP头 + int iphdr_len = addr_ipv6 ? 0 : ipheader->ihl * 4; int icmp_len = nrecv - iphdr_len; + uint16_t cksum = 0, cksum1 = 0; if (icmp_len == sendbytes) { - icmp_res = (icmp_t*)(recvbuf + ipheader->ihl*4); - if (icmp_res->icmp_type == ICMP_ECHOREPLY && - icmp_res->icmp_id == pid16 && - icmp_res->icmp_seq == seq) { + icmp_res = (icmp_t *)(recvbuf + iphdr_len); + if (!addr_ipv6) { + // IPv4校验需先把数据包中的校验码段置0 + cksum = icmp_res->icmp_cksum; + icmp_res->icmp_cksum = 0; + cksum1 = checksum((uint8_t *)icmp_res, icmp_len); + } + if ((icmp_res->icmp_type == (addr_ipv6 ? ICMPV6_ECHOREPLY : ICMP_ECHOREPLY)) && (addr_ipv6 || (cksum == cksum1)) && // IPv6不检验校验码 + icmp_res->icmp_id == pid16 && icmp_res->icmp_seq == seq) { valid = true; } } if (valid == false) { - printd("recv invalid icmp packet!\n"); + printd("recv invalid icmp packet! recvsz: %d, icmphsz: %d, type: %d, code: %d, checksum: %d == %d, id: %d, seq: %d\n", nrecv, icmp_len, icmp_res->icmp_type, icmp_res->icmp_code, cksum, cksum1, icmp_res->icmp_id, icmp_res->icmp_seq); continue; } - rtt = (end_hrtime-start_hrtime) / 1000.0f; + rtt = (end_hrtime - start_hrtime) / 1000.0f; min_rtt = MIN(rtt, min_rtt); 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); + if (addr_ipv6) + printd("%d bytes from %s: icmp_seq=%u 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); fflush(stdout); ++ok_cnt; if (cnt > 0) hv_sleep(1); // sleep a while, then agian @@ -113,9 +136,9 @@ int ping(const char* host, int cnt) { end_tick = gettick_ms(); printd("--- %s ping statistics ---\n", host); printd("%d packets transmitted, %d received, %d%% packet loss, time %d ms\n", - send_cnt, recv_cnt, (send_cnt-recv_cnt)*100/(send_cnt==0?1:send_cnt), end_tick-start_tick); + send_cnt, recv_cnt, (send_cnt - recv_cnt) * 100 / (send_cnt == 0 ? 1 : send_cnt), end_tick - start_tick); printd("rtt min/avg/max = %.3f/%.3f/%.3f ms\n", - min_rtt, total_rtt/(ok_cnt==0?1:ok_cnt), max_rtt); + min_rtt, total_rtt / (ok_cnt == 0 ? 1 : ok_cnt), max_rtt); closesocket(sockfd); return ok_cnt; From 16f63135ccb1a7c3f7dade0aa7f970518fefe345 Mon Sep 17 00:00:00 2001 From: ningss Date: Tue, 8 Apr 2025 14:14:57 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20icmp=20recvfrom=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E7=BD=AE0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/icmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/protocol/icmp.c b/protocol/icmp.c index ade5ee46d..084131fb9 100644 --- a/protocol/icmp.c +++ b/protocol/icmp.c @@ -91,6 +91,7 @@ int ping(const char *host, int cnt) { } ++send_cnt; addrlen = sizeof(peeraddr); + memset(recvbuf, 0, sizeof(recvbuf)); int nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen); if (nrecv < 0) { perror("recvfrom"); From f98f2a2466ef0c45efa223ae6523857c7d500468 Mon Sep 17 00:00:00 2001 From: ningss Date: Tue, 8 Apr 2025 16:09:08 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20icmp=20recvfrom=E9=87=8D=E8=AF=95?= =?UTF-8?q?=E8=87=B3=E8=B6=85=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/icmp.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/protocol/icmp.c b/protocol/icmp.c index 084131fb9..dbf405a25 100644 --- a/protocol/icmp.c +++ b/protocol/icmp.c @@ -91,12 +91,25 @@ int ping(const char *host, int cnt) { } ++send_cnt; addrlen = sizeof(peeraddr); - memset(recvbuf, 0, sizeof(recvbuf)); - int nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen); - if (nrecv < 0) { - perror("recvfrom"); - continue; + bool is_recv_fail = false; + int nrecv; + while (true) { + memset(recvbuf, 0, sizeof(recvbuf)); + nrecv = recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, &peeraddr.sa, &addrlen); + if (nrecv < 0) { + end_hrtime = gethrtime_us(); + rtt = (end_hrtime - start_hrtime) / 1000.0f; + if(rtt >= PING_TIMEOUT){ + is_recv_fail = true; + perror("recvfrom"); + break; + } + hv_msleep(1); + } else { + break; + } } + if(is_recv_fail) continue; ++recv_cnt; end_hrtime = gethrtime_us(); // check valid