I wrote it for test purpose.
For Win target I uses MinGW and GCC.
/* $Id: ping.c,v 1.1 2019/02/20 13:01:37 ziggi Exp ziggi $ */ #ifdef __WINNT__ #define __WINNT 1 #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #include <limits.h> #include <unistd.h> #ifdef __WINNT__ #include <sys/types.h> #include <sys/stat.h> #define _WIN32_WINNT 0x0501 #include <winsock2.h> #include <ws2tcpip.h> #include <pshpack1.h> #else #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <netdb.h> #endif #ifdef __WINNT__ struct ip { u_char ip_hl:4; /* header length */ u_char ip_v:4; /* version */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src; struct in_addr ip_dst; /* source and dest address */ } __packed; struct icmp { u_char icmp_type; u_char icmp_code; u_short icmp_cksum; u_short icmp_id; u_short icmp_seq; }; #endif typedef struct ip ip_hdr_t; typedef struct icmp icmp_hdr_t; #define HOST "v5.unix7.org" uint16_t icmpv4_checksum(const uint16_t *const data, const size_t byte_sz) { if (0 != (byte_sz & 1)) { fprintf(stderr, "# wrong number of bytes %u must be even", (int)byte_sz); } uint32_t accu = 0; for (size_t i = 0; i < (byte_sz >> 1); ++i) { accu = accu + data[i]; } while (accu >> 16) { accu = (accu & 0xffff) + (accu >> 16); } const uint16_t checksum = ~accu; return checksum; } int __exit(void) { #ifdef __WINNT__ WSACleanup(); #endif exit(1); } int main(int argc, char **argv) { #ifdef __WINNT__ WSADATA wsaData; #define WSVERSION 0x0202 int iResult = WSAStartup(WSVERSION, &wsaData); if (iResult != 0) { printf("# wsastartup() failed: %d\n", iResult); __exit(); } #endif struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; struct addrinfo *result = NULL; int retval; if ((retval = getaddrinfo(HOST, NULL, &hints, &result)) != 0) { printf("# getaddrinfo() failed with error: %d\n", retval); __exit(); } struct sockaddr_in *sockaddr = NULL; for(struct addrinfo *ptr = result; ptr != NULL ;ptr = ptr->ai_next) { switch (ptr->ai_family) { case AF_INET: sockaddr = (struct sockaddr_in *)ptr->ai_addr; printf("# host %s have ipv4 address %s\n", HOST, inet_ntoa(sockaddr->sin_addr)); break; default: break; } if (sockaddr != NULL) { break; } } struct sockaddr_in dest_sockaddr; memcpy(&dest_sockaddr, sockaddr, sizeof(dest_sockaddr)); freeaddrinfo(result); int sock; if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { printf("# socket creation failed\n"); __exit(); } #define SOCKET_ERROR (-1) const int ttl = 16; #ifdef __WINNT__ if (setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)) < 0) { fprintf(stderr, "# setting ttl setsockopt failed\n"); __exit(); } #else if (setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) { fprintf(stderr, "# setting ttl setsockopt failed\n"); __exit(); } #endif #define PAYLOAD_LEN 4 #define OBUFFER_SIZE sizeof(icmp_hdr_t) + PAYLOAD_LEN #ifndef ICMP_ECHO #define ICMP_ECHO 8 #endif #ifndef ICMP_ECHOREPLY #define ICMP_ECHOREPLY 0 #endif #ifndef ICMP_CODE #define ICMP_CODE 0 #endif char obuffer[OBUFFER_SIZE]; icmp_hdr_t *icmp_hdr; icmp_hdr = (icmp_hdr_t *)obuffer; icmp_hdr->icmp_type = ICMP_ECHO; icmp_hdr->icmp_code = ICMP_CODE; icmp_hdr->icmp_id = htons(1234); icmp_hdr->icmp_cksum = 0; icmp_hdr->icmp_seq = htons(4567); char *payload = obuffer + sizeof(icmp_hdr_t); memset(payload, '<', PAYLOAD_LEN); icmp_hdr->icmp_cksum = icmpv4_checksum((uint16_t *)obuffer, OBUFFER_SIZE); sendto(sock, (char *)obuffer, OBUFFER_SIZE, 0, (struct sockaddr *)&dest_sockaddr, sizeof(dest_sockaddr)); #define IBUFFER_SIZE 2048 #define SLEEP_TIME 1 // 1 ms #define DELAY_TIME 1000 // 1 sec char ibuffer[IBUFFER_SIZE]; struct sockaddr_in src_sockaddr; memset(&src_sockaddr, 0, sizeof(src_sockaddr)); socklen_t src_sockaddr_size = sizeof(src_sockaddr); int i = 0, count = DELAY_TIME / SLEEP_TIME; while (1) { ssize_t res_count = recvfrom(sock, (char *)ibuffer, IBUFFER_SIZE, 0, (struct sockaddr *)&src_sockaddr, &src_sockaddr_size); if (res_count > 0) { printf("# received %d bytes\n", (int)res_count); printf("# icmp from %s\n", inet_ntoa(src_sockaddr.sin_addr)); ip_hdr_t *ip_hdr = (struct ip *)ibuffer; printf("# responce ttl %d\n", ip_hdr->ip_ttl); size_t ip_header_len = ip_hdr->ip_hl >> 2; struct icmp *icmp_header = (struct icmp *)(ip_hdr + ip_header_len); if (icmp_header->icmp_type == ICMP_ECHOREPLY) { printf("# type ICMP_ECHOREPLY\n"); } printf("# icmp id %d\n", ntohs(icmp_header->icmp_id)); printf("# icmp seq %d\n", ntohs(icmp_header->icmp_seq)); break; } i++; if (i > count) { printf("# icmp timeout\n"); break; } #ifdef __WINNT__ Sleep(SLEEP_TIME); #else usleep(SLEEP_TIME * 1000); #endif } close(sock); #ifdef __WINNT__ WSACleanup(); #endif } /* EOF */