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*)
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.
ICMP type 30 is specifically designated for traceroute and is labeled as an "Information Request".
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With