User Tools

Site Tools


This is an old revision of the document!


Ping sample

I wrote it for test purpose.

file.c
/* $Id: ping.c,v 1.1 2019/02/20 13:01:37 ziggi Exp ziggi $ */
 
#include <sys/types.h>
#include <sys/stat.h>
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include <sys/socket.h>
#include <arpa/inet.h>
 
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
 
#include <netdb.h>
 
#include <unistd.h>
#include <limits.h>
 
 
uint16_t icmp_checksum(const uint16_t * const data, const size_t byte_sz) {
    if (0 != (byte_sz & 1)) {
        fprintf(stderr, "# wrong number of bytes %zu must be even", byte_sz);
        exit(1);
    }
    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;
}
 
#define HOST "wiki.unix7.org"
 
int main(int argc, char **argv) {
 
    const char *host = HOST;
 
    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;
 
    if (getaddrinfo(HOST, NULL, &hints, &result)) {
        fprintf(stderr, "# cannot resolve host name %s\n", host);
        exit(1);
    }
 
    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;
    memset(&dest_sockaddr, 0, sizeof(dest_sockaddr));
    memcpy(&dest_sockaddr, sockaddr, sizeof(dest_sockaddr));
    freeaddrinfo(result);
 
#define PAYLOAD_LEN 4
#define OBUFFER_LEN sizeof(struct icmp) + PAYLOAD_LEN
 
    char obuffer[ OBUFFER_LEN ];
    memset(obuffer, 0, OBUFFER_LEN);
 
    struct icmp *icmp_header = (struct icmp *)obuffer;
 
    icmp_header->icmp_type = ICMP_ECHO;
    icmp_header->icmp_code = 0;
    icmp_header->icmp_cksum = 0;
    icmp_header->icmp_seq = htons(12345);
    icmp_header->icmp_id = htons(45678);
 
    char *payload = obuffer + sizeof(icmp_header);
    memset(payload, '<', PAYLOAD_LEN);
 
    icmp_header->icmp_cksum = icmp_checksum((uint16_t *)obuffer, OBUFFER_LEN);
 
    int osock;
    if ((osock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
        fprintf(stderr, "# raw output socket create failed\n");
        exit(1);
    }
 
    const ssize_t sent_bytes = sendto(
        osock,
        obuffer,
        OBUFFER_LEN,
        0,
        (struct sockaddr *)&dest_sockaddr, 
        sizeof(dest_sockaddr)
    );
 
#define IBUFFER_LEN IP_MAXPACKET
    char ibuffer[IBUFFER_LEN];
    memset(ibuffer, 0, IBUFFER_LEN);
 
    struct sockaddr_in src_sockaddr;
    socklen_t src_sockaddr_len = sizeof(src_sockaddr);
    memset(&src_sockaddr, 0, sizeof(src_sockaddr));
 
    int isock;
    if ((isock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
        fprintf(stderr, "# raw input socket create failed\n");
        exit(1);
    }
 
#define SLEEP_TIME 1000         // 1ms
#define DELAY_TIME 1000 * 1000  // 1 sec
 
    int i = 0, count = DELAY_TIME / SLEEP_TIME;
    while (1) {
 
        ssize_t res_count = recvfrom(
            isock,
            ibuffer,
            IBUFFER_LEN,
            0,
            (struct sockaddr *)&src_sockaddr,
            &src_sockaddr_len
        );
 
        if (res_count > 0) {
            printf("# received %zd bytes\n", res_count);
 
            printf("# icmp from %s\n", inet_ntoa(src_sockaddr.sin_addr));
 
            struct ip *ip = (struct ip *)ibuffer;
            printf("#   responce ttl %d\n", ip->ip_ttl);
 
            size_t ip_header_len = ip->ip_hl >> 2;
 
            struct icmp *icmp_header = (struct icmp *)(ip + 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;
        }
        usleep(SLEEP_TIME);
    }
    close(osock);
    close(isock);
}

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