Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

1. Implement a “ping” program using raw socket. This “ping” program only needs t

ID: 3763642 • Letter: 1

Question

1. Implement a “ping” program using raw socket.
This “ping” program only needs to support IPv4 and ICMPv4, not IPv6 and ICMPv6.
You may use the “ping” program from the “Unix Network Programming” textbook
as the starting point for your implementation. If you do so, please remove the IPv6
and ICMPv6 related code from the textbook “ping” program.
This “ping” program should be multi-threaded. Instead of sending the “ping”
probes (i.e. ICMP echo requests) from an alarm signal handler, this program should
use one thread to send ICMP echo requests and another thread to receive ICMP
echo replies.
The IP TTL should be set to 32 for every ICMP echo request sent by this program.
Your submission should be self-sufficient and not depend on any source code or
library that are not available from a standard Linux distribution.

Submission

The implementation should be in C/C++ on Linux.

submission:

README: A file that:
o describes what each program does and how to compile and run the programs;
o provides all the references (besides textbooks/lectures) where you get help.
Source code
Makefile: “make” should compile all your programs.
RESULTS: A file that contains the sample output of each program.

You need to submit all these files in a single zip file.

Explanation / Answer


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <string.h>
#include <unistd.h>


char dst_addr[20];
char src_addr[20];

unsigned Sum(unsigned short *, int);
void Average(char**, char*, char* );
void usage();
char* getip();
char* toip(char*);

int main(int argc, char* argv[])
{
    struct iphdr* ip;
    struct iphdr* ip_reply;
    struct icmphdr* icmp;
    struct sockaddr_in connection;
    char* packet;
    char* buffer;
    int sockfd;
    int optval;
    int addrlen;
    int siz;

   
    if (getuid() != 0)
    {
    fprintf(stderr, "%s: root privelidges needed ", *(argv + 0));
    exit(EXIT_FAILURE);
    }

    Average(argv, dst_addr, src_addr);
    strncpy(dst_addr, toip(dst_addr), 20);
    strncpy(src_addr, toip(src_addr), 20);
    printf("Source address: %s ", src_addr);
    printf("Destination address: %s ", dst_addr);

    packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
    buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
  
   
    ip = (struct iphdr*) packet;
    icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));

    ip->ihl          = 5;
    ip->version      = 4;
    ip->tos          = 0;
    ip->tot_len      = sizeof(struct iphdr) + sizeof(struct icmphdr);
    ip->id           = htons(0);
    ip->frag_off     = 0;
    ip->ttl          = 64;
    ip->protocol     = IPPROTO_ICMP;
    ip->saddr            = inet_addr(src_addr);
    ip->daddr            = inet_addr(dst_addr);
    ip->check            = in_cksum((unsigned short *)ip, sizeof(struct iphdr));
   
    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
    {
    perror("socket");
    exit(EXIT_FAILURE);
    }
   

   
    setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));

    icmp->type           = ICMP_ECHO;
    icmp->code           = 0;
    icmp->un.echo.id     = random();
    icmp->un.echo.sequence   = 0;
    icmp-> checksum      = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
   
   
    connection.sin_family = AF_INET;
    connection.sin_addr.s_addr = inet_addr(dst_addr);
   
    sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
    printf("Sent %d byte packet to %s ", ip->tot_len, dst_addr);

    addrlen = sizeof(connection);
    if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)
    {
    perror("recv");
    }
    else
    {
    printf("Received %d byte reply from %s: ", siz , dst_addr);
        ip_reply = (struct iphdr*) buffer;
    printf("ID: %d ", ntohs(ip_reply->id));
    printf("TTL: %d ", ip_reply->ttl);
    }

    free(packet);
    free(buffer);
    close(sockfd);
    return 0;
}
void Average(char** argv, char* dst, char* src)
{
    int i;
    if(!(*(argv + 1)))
    {
    usage();
    exit(EXIT_FAILURE);
    }
    if (*(argv + 1) && (!(*(argv + 2))))
    {
    strncpy(dst, *(argv + 1), 15);
    strncpy(src, getip(), 15);
    return;
    }
    else if ((*(argv + 1) && (*(argv + 2))))
    {
    strncpy(dst, *(argv + 1), 15);
    i = 2;
    while(*(argv + i + 1))
    {
        if (strncmp(*(argv + i), "-s", 2) == 0)
        {
        strncpy(src, *(argv + i + 1), 15);
        break;
        }
        i++;
    }
    }

}

void usage()
{
    fprintf(stderr, " Usage: pinger [destination] <-s [source]> ");
    fprintf(stderr, "Destination must be provided ");
    fprintf(stderr, "Source is optional ");
}

char* getip()
{
    char buffer[256];
    struct hostent* h;
   
    gethostname(buffer, 256);
    h = gethostbyname(buffer);
   
    return inet_ntoa(*(struct in_addr *)h->h_addr);
   
}

char* toip(char* address)
{
    struct hostent* h;
    h = gethostbyname(address);
    return inet_ntoa(*(struct in_addr *)h->h_addr);
}

unsigned Sum(unsigned short *addr, int len)
{
    register int sum = 0;
    u_short answer = 0;
    register u_short *w = addr;
    register int nleft = len;

    while (nleft > 1)
    {
      sum += *w++;
      nleft -= 2;
    }
    /* mop up an odd byte, if necessary */
    if (nleft == 1)
    {
      *(u_char *) (&answer) = *(u_char *) w;
      sum += answer;
    }
  
    sum = (sum >> 32) + (sum & 0xffff);     
    sum += (sum >> 32);           
    answer = ~sum;              /* truncate to 32 bits */
    return (answer);
}