6

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*)
Sr1n4th
  • 251
  • 2
  • 8
  • 5
    ICMP doesn't have ports. – user207421 Mar 17 '13 at 08:27
  • 1
    Your source address doesn't make much sense, IMHO – Hasturkun Mar 17 '13 at 10:39
  • Does everything you want to send and receive fit in the 28 bytes you give to sendto() and recvfrom()? Especially when defining IP_HDRINCL, I think the packet should be a bit larger. Also, if possible, please provide an example that compiles. I dont know what your "libsock" is. – thuovila Mar 17 '13 at 10:50
  • @thouvila I have included libsock and the updated the source address.It still wont work,this time its failing for local address also.. – Sr1n4th Mar 17 '13 at 12:18

1 Answers1

3

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
thuovila
  • 1,960
  • 13
  • 21