User Tools

Site Tools


This is an old revision of the document!


pingw3.c
# 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) {
                //printf("# received %d bytes\n", (int)res_count);
 
                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);
 
                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
}

Out

$ cc -o pingw3 pingw3.c && sudo ./pingw3
# host v5.unix7.org have ipv4 address 93.171.216.21
# ttl= 1 icmp type 11 from 192.168.56.1
# ttl= 2 icmp type 11 from 212.48.195.247
# ttl= 3 icmp type 11 from 212.48.198.234
# ttl= 4 icmp type 11 from 87.226.133.237
# ttl 5 icmp timeout
# ttl= 6 icmp type 11 from 4.69.137.90
# ttl= 7 icmp type 11 from 212.73.241.250
# ttl 8 icmp timeout
# ttl= 9 icmp type 0 from 93.171.216.21
#   type ICMP_ECHOREPLY
#   icmp id 1234
#   icmp seq 4567