# cat Ping/pingw3.c
/* $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);
#define SOCKET_ERROR (-1)
#define PAYLOAD_LEN 4
#define OBUFFER_SIZE sizeof(icmp_hdr_t) + PAYLOAD_LEN
#define ICMP_ECHOREPLY 0
#define ICMP_ECHO 8
#define ICMP_CODE 0
int ttl;
#define MAX_TTL 12
for (ttl = 1; ttl < MAX_TTL; ttl++) {
int sock;
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
printf("# socket creation failed\n");
__exit();
}
#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
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);
if (sendto(sock, (char *)obuffer, OBUFFER_SIZE, 0, (struct sockaddr *)&dest_sockaddr, sizeof(dest_sockaddr)) < 0) {
fprintf(stderr, "# sendto failed\n");
__exit();
}
#define IBUFFER_SIZE 204
#define SLEEP_TIME 1 // 1 ms
#define DELAY_TIME 2 * 1000 // 2 sec
#define MAX_COUNT DELAY_TIME / SLEEP_TIME
char ibuffer[IBUFFER_SIZE];
memset(ibuffer, 0, 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;
while (i < MAX_COUNT) {
i++;
ssize_t res_count = recvfrom(sock, (char *)ibuffer, IBUFFER_SIZE, MSG_DONTWAIT,
(struct sockaddr *)&src_sockaddr, &src_sockaddr_size);
if (res_count > 0) {
ip_hdr_t *ip_hdr = (struct ip *)ibuffer;
size_t ip_header_len = ip_hdr->ip_hl >> 2;
struct icmp *icmp_header = (struct icmp *)(ip_hdr + ip_header_len);
printf("# ttl= %d icmp type %d from %s\n", ttl,
icmp_header->icmp_type, inet_ntoa(src_sockaddr.sin_addr));
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));
exit(0);
}
break;
}
if (i == MAX_COUNT) {
printf("# ttl %d icmp timeout\n", ttl);
break;
}
#ifdef __WINNT__
Sleep(SLEEP_TIME);
#else
usleep(SLEEP_TIME * 1000);
#endif
}
close(sock);
}
#ifdef __WINNT__
WSACleanup();
#endif
}