Implementing traceroute using icmp in C
Asked Answered
S

1

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*)
Schoof answered 17/3, 2013 at 7:14 Comment(4)
ICMP doesn't have ports.Glendon
Your source address doesn't make much sense, IMHOSmashing
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.Parapet
@thouvila I have included libsock and the updated the source address.It still wont work,this time its failing for local address also..Schoof
P
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
Parapet answered 17/3, 2013 at 15:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.