User Tools

Site Tools


Ping sample

I wrote it for test purpose.

For Win target I uses MinGW and GCC.

file.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);
 
    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 */

Out

# host wiki.unix7.org have ipv4 address 93.171.216.21
# received 52 bytes
# icmp from 93.171.216.21
#   responce ttl 55
#   type ICMP_ECHOREPLY
#   icmp id 45678
#   icmp seq 12345

First PagePrevious PageBack to overviewNext PageLast Page