Question

My program sends an icmp request to the specified host.

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define ICMP_DATALEN    4
#define IP4_HDRLEN              20
#define ICMP_HDRLEN             8

uint16_t                                checksum (uint16_t *addr, int len)
{
    int nleft = len;
    int sum = 0;
    uint16_t *w = addr;
    uint16_t answer = 0;

    while (nleft > 1) {
            sum += *w++;
            nleft -= sizeof (uint16_t);
    }

    if (nleft == 1) {
            *(uint8_t *) (&answer) = *(uint8_t *) w;
            sum += answer;
    }

    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    answer = ~sum;
    return (answer);
}

int                                             main(int ac, char **av)
{
    int                              icmp_socket;
    uint8_t                          data[ICMP_DATALEN];
    unsigned char                    datagram[IP_MAXPACKET];
    int                              ip_flags[4];
    struct ip                        *iph = (struct ip *) datagram;
    struct icmp                      *icmph = (struct icmp *) (datagram + IP4_HDRLEN);
    struct sockaddr_in               dst;
    int                              one = 1;
    int                              *val = &one;

    if (ac != 3)
    {
            fprintf(stderr, "usage: %s <source adress> <target adress>\n", av[0]);
            return (1);
    }

    if ((icmp_socket = socket(AF_INET, SOCK_RAW, 1)) == -1)
    {
            perror("socket");
            exit(1);
    }
    if (setsockopt(icmp_socket, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
    {
            perror("setsockopt");
            exit(1);
    }

    memset(datagram, 0, IP_MAXPACKET);

    //prepare ipv4 header data
    memset((void*)&dst, 0, sizeof(dst));
    dst.sin_family = AF_INET;
    inet_pton(AF_INET, av[2], &(dst.sin_addr));
    ip_flags[0] = 0;
    ip_flags[1] = 0;
    ip_flags[2] = 0;
    ip_flags[3] = 0;

    //fill in ipv4 header
    iph->ip_hl = IP4_HDRLEN / sizeof(uint32_t);
    iph->ip_v = 4;
    iph->ip_tos = 0;
    iph->ip_len = (IP4_HDRLEN + ICMP_HDRLEN + ICMP_DATALEN);
    iph->ip_id = 666;
    iph->ip_off = (ip_flags[0] << 15)
                                            + (ip_flags[1] << 14)
                                            + (ip_flags[2] << 13)
                                            + ip_flags[3];
    iph->ip_ttl = 255;
    iph->ip_p = IPPROTO_ICMP;
    iph->ip_src.s_addr = inet_addr(av[1]);
    iph->ip_dst.s_addr = dst.sin_addr.s_addr;
    iph->ip_sum = 0;
    iph->ip_sum = checksum((uint16_t *)datagram, IP4_HDRLEN);

    //prepare icmp data
    data[0] = '4';
    data[1] = '2';
    data[2] = '4';
    data[3] = '2';

    //fill in icmp header
    icmph->icmp_type = ICMP_ECHO;
    icmph->icmp_code = 0;
    icmph->icmp_id = htons(666);
    icmph->icmp_seq = htons(0);
    memcpy(datagram + IP4_HDRLEN + ICMP_HDRLEN, data, ICMP_DATALEN);
    icmph->icmp_cksum = 0;
    icmph->icmp_cksum = checksum((uint16_t *)datagram + IP4_HDRLEN, (ICMP_HDRLEN + ICMP_DATALEN));

    int             i = 0;

    printf("sending packet:\n\n");
    while (i < (IP4_HDRLEN + ICMP_HDRLEN + ICMP_DATALEN))
    {
            printf("%02x", datagram[i++]);
            if (i % 2 == 0)
                    printf(" ");
            if (i % 16 == 0)
                    printf("\n");
    }
    printf("ip header checksump: %hx\n", iph->ip_sum);
    printf("icmp header checksump: %hx\n", icmph->icmp_cksum);

    if (sendto(icmp_socket, datagram, (IP4_HDRLEN + ICMP_HDRLEN + ICMP_DATALEN), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0)
    {
            perror("sendto");
            exit(1);
    }
    close(icmp_socket);
    return (0);
}

I watched the network with tcpdump and the packet is sent, but I never recieve an answer, as I would with the ping command. I hope you can help me !

Was it helpful?

Solution

The checksum is in network byte order.

You need to read the bytes being added to the checksum using ntohs, and write back the checksum with htons.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top