Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing traceroute using icmp in C

Tags:

c

sockets

icmp

I am trying to implement traceroute using icmp raw sockets by constructing the appropriate ip header and icmp header.The port number i am using is 7 and i have calculated the checksums.The hop limit is incremented each time and a packet is sent till the reply message contains the echo reply of type 0.

#include "libsock"
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>


unsigned short
csum (unsigned short *buf, int nwords)
{
  unsigned long sum;
  for (sum = 0; nwords > 0; nwords--)
    sum += *buf++;
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  return ~sum;
}

int
main (int argc, char *argv[])
{
  if (argc != 2)
    {
      printf ("need destination for tracert\n");
      exit (0);
    }
  int sfd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
  char buf[4096] = { 0 };
  struct ip *ip_hdr = (struct ip *) buf;
  int hop = 0;

  int one = 1;
  const int *val = &one;
  if (setsockopt (sfd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
    printf ("Cannot set HDRINCL!\n");

  struct sockaddr_in addr;
  addr.sin_port = htons (7);
  addr.sin_family = AF_INET;
  inet_pton (AF_INET, argv[1], &(addr.sin_addr));


  while (1)
    {
      ip_hdr->ip_hl = 5;
      ip_hdr->ip_v = 4;
      ip_hdr->ip_tos = 0;
      ip_hdr->ip_len = 20 + 8;
      ip_hdr->ip_id = 10000;
      ip_hdr->ip_off = 0;
      ip_hdr->ip_ttl = hop;
      ip_hdr->ip_p = IPPROTO_ICMP;
      inet_pton (AF_INET, "172.30.104.59", &(ip_hdr->ip_src));
      inet_pton (AF_INET, argv[1], &(ip_hdr->ip_dst));
      ip_hdr->ip_sum = csum ((unsigned short *) buf, 9);

      struct icmphdr *icmphd = (struct icmphdr *) (buf + 20);
      icmphd->type = ICMP_ECHO;
      icmphd->code = 0;
      icmphd->checksum = 0;
      icmphd->un.echo.id = 0;
      icmphd->un.echo.sequence = hop + 1;
      icmphd->checksum = csum ((unsigned short *) (buf + 20), 4);
      sendto (sfd, buf, 28, 0, SA & addr, sizeof addr);
      char buff[4096] = { 0 };
      struct sockaddr_in addr2;
      socklen_t len = sizeof (struct sockaddr_in);
      recvfrom (sfd, buff, 28, 0, SA & addr2, &len);
      struct icmphdr *icmphd2 = (struct icmphdr *) (buff + 20);
      if (icmphd2->type != 0)
    printf ("hop limit:%d Address:%s\n", hop, inet_ntoa (addr2.sin_addr));
      else
    {
      printf ("Reached destination:%s with hop limit:%d\n",
          inet_ntoa (addr2.sin_addr), hop);
      exit (0);
    }

      hop++;
    }

  return 0;
}

When the input ie argv[1] is "127.0.0.1" the o/p is

hop limit:0 Address:127.0.0.1

Reached destination:127.0.0.1 with hop limit:1

but for other addresses present in my lan for whom tracepath works my program blocks at recvfrom.

Can you please point out the reasons?

Thank you.

Here's libsock:-

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>
#include<pthread.h>
#include<poll.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<signal.h>
#include<sys/sem.h>
#include<poll.h>
#include<pthread.h>
#include<sys/select.h>
#include<sys/un.h>
#define SA (struct sockaddr*)
like image 719
Sr1n4th Avatar asked Mar 17 '13 07:03

Sr1n4th


People also ask

How is ICMP used in traceroute?

Traceroute uses ICMP's Ping command to find out how many different devices are between the computer initiating the traceroute and the target. This command works by manipulating the packets time to live value or TTL.

Does ICMP include traceroute?

ICMP type 30 is specifically designated for traceroute and is labeled as an "Information Request".

What is ICMP How does it work with traceroute and ping?

ICMP was designed to be an error reporting protocol and has a wide variety of uses that we won't go into here. Ping uses two ICMP message types: type 8 (Echo Request) and type 0 (Echo Reply). When you issue a ping command, the source sends an ICMP Echo Request to the destination.


1 Answers

If you want to build the IP headers by hand, you have to set the source address to an IP which has routability to the IP address you give as a destination. E.g. for localhost, you can set the source to 127.0.0.1, since localhost "can ping" localhost (i.e. has routability there).

The sizes you give the send and receive seem really too small. I made the following changes on my home computer (it is behind a NAT device, thus the 192.168.1.0/24 address).

inet_pton (AF_INET, "192.168.1.168", &(ip_hdr->ip_src));
....
sendto (sfd, buf, sizeof(struct ip) + sizeof(struct icmphdr), 0, SA & addr, sizeof addr);
....
recvfrom (sfd, buff, sizeof(buff), 0, SA & addr2, &len);

Example output:

thuovila@glx:~/src/so$ sudo ./a.out 128.214.248.132
hop limit:0 Address:192.168.1.1
hop limit:1 Address:192.168.1.1
hop limit:2 Address:91.156.128.1
hop limit:3 Address:139.97.9.58
hop limit:4 Address:139.97.6.209
hop limit:5 Address:139.97.6.250
hop limit:6 Address:193.110.224.14
hop limit:7 Address:193.166.255.93
Reached destination:128.214.248.132 with hop limit:8
like image 167
thuovila Avatar answered Oct 12 '22 13:10

thuovila