Click here to Skip to main content
15,893,622 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to write a very simple version of the traceroute program using raw sockets and ICMP. But when I run it i just always get an endless loop of echo requests by myself back.

Objective-C
#include <netinet/ip.h>         
#include <netinet/ip_icmp.h>        
#include <sys/socket.h>         
#include <stdlib.h>             
#include <stdio.h>              
#include <sys/types.h>
#include <errno.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <ifaddrs.h>

int mysock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
int ttl = 0;                    
char buffr[4069] = { 0 };
struct ip *myIpHeader = (struct ip*)buffr;      
struct ifaddrs *ifa;
getifaddrs(&ifa);   


then i just do some input checks and set setsocketopt to HDRINCL

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


then the endless while loop where i set up the ip and icmp header like this

Objective-C
myIpHeader->ip_v = 4;                           
myIpHeader->ip_hl = 5;                      
myIpHeader->ip_tos = 0;                                             
myIpHeader->ip_len = 20+8;
myIpHeader->ip_off = 0;                     
myIpHeader->ip_p = IPPROTO_ICMP;                
inet_pton(AF_INET, argv[1], &(myIpHeader->ip_dst));
inet_pton(AF_INET, ifa->ifa_name, &(myIpHeader->ip_src));
myIpHeader->ip_sum = 0;
myIpHeader->ip_id = htonl(12345);                               
myIpHeader->ip_ttl = ttl;

struct icmphdr *myicmphead = (struct icmphdr *) (buffr + 20);        
myicmphead->type = 8; 
myicmphead->code = 0;               
myicmphead->checksum = 0;


then follows send and recv

Objective-C
sendto(mysock, buffr , sizeof (struct ip) + sizeof (struct icmphdr), 0, (struct sockaddr*)&cliAddr, sizeof cliAddr);
char buff[4096] = { 0 };            
struct sockaddr_in serverAddr;      
socklen_t inlen = sizeof(struct sockaddr_in);

recvfrom(mysock, buff, sizeof(buff), 0, (struct sockaddr*) & serverAddr, &inlen);
struct icmphdr *icmphd2 = (struct icmphdr *) (buff + 20);


and then i just check if the type i receive equals 0 if so the destination is reached and i exit if not im gonna print the ttl and address and increase the ttl

Objective-C
printf("ttl: %d Address:%s\n", ttl, inet_ntoa(serverAddr.sin_addr));


But like i said i just print out the source address i put in the ip head in an endless loop. Basically looking like that:(I just put placeholders for ip addresses and so on)

trace route to '...' (IP: 160.....) 
ICMP msgtype=8, code=0 
ttl limit: 0 Address 127.0.0.1 
ICMP msgtype=8, code=0 
ttl limit: 1 Address 127.0.0.1 
ICMP msgtype=8, code=0 
ttl limit: 2 Address 127.0.0.1
ICMP msgtype=8, code=0 
ttl limit: 3 Address 127.0.0.1 
ICMP msgtype=8, code=0 
ttl limit: 4 Address 127.0.0.1


and so on as example what i get
I would really appreciate any tips how i could solve this.

What I have tried:

Thanks to Jochen Arndt, I could solve this problem and now put the right addresses. But now I got a new problem. The program somehow just gets the first rcv, so I guess I forgot to do something before I receive again because it says the resource is temporarily unavailable as error for receive(when I put it to not wait for an reply). Any idea what I forgot?
Posted
Updated 15-Aug-17 12:26pm
v2

You are not enumerating the existing network interfaces but use only the first returned by getifaddrs(). You should check if that is an existing INET IPv4 interface and not something else or the loopback interface.

You are also passing ifa->ifa_name to inet_pton(). But that is the name of the interface (e.g. localhost, eth0) while inet_pton() expects an IP address as string (e.g. "127.0.0.1"). You probably want to use ifa->ifa_addr instead which is already in binary format.

There may be also other errors but the above have to be fixed before checking if your send data are correct.

I suggest to read the documentation of the used functions:
getifaddrs(3) - Linux manual page[^]
inet_pton(3) - Linux manual page[^]

You should also always check the return value of functions that return a state. If you would have done that for inet_pton(), you would have recognised that the call failed.
 
Share this answer
 
Comments
P1ll0wTh13f 15-Aug-17 11:37am    
Thanks this helped a lot, I should have looked into that more form the beginning and checked the return values. Now I set them up correctly but I still have a problem, because the program somehow just gets the first rcv and after that never goes on but also doesn't terminate so I guess i forgot to do smth before i receive again because it says the resource is temporarily unavailable as error for receive. Any idea what i forgot?
for some reason the
C++
inet_ntoa(serverAddr.sin_addr)
i used in printing rewrote the dest address to the one i got as source from icmp. Now it works tho.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900