Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a basic traceroute script in C

I have to write a trceroute script but I'm not sure if my attempts are correct.

Right now I'm doing it like that (please correct me if I'm doing wrong or clumsy):

  1. Got an struct for ip- and udpheader
  2. A checksum function
  3. Opening 2 sockets: One for sending UDP-packets in SOCK_RAW mode (to manipulate ttl) and one to receive ICMP-answers from the routers.
  4. Using sendto() to send UDP packet
  5. Having no clue how to receive and process an ICMP answer

Are there any more comfortable ways to change the TTL than using sock_raw where I have to define all header stuff by myself? What parameters should I use for socket() when opening ICMP sock? How to receive the ICMP answer?

like image 991
d.hill Avatar asked Feb 03 '11 13:02

d.hill


People also ask

How traceroute works step by step?

Here's how it works: The user invokes the traceroute (or tracert) command and specifies a target host. If the host is specified in the form of a domain name, traceroute will attempt to resolve it. Traceroute sends a data packet towards the target with the TTL value set to “1”.

What is the traceroute command?

Traceroute – The traceroute command is used to determine the path between two connections. Often a connection to another device will have to go through multiple routers. The traceroute command will return the names or IP addresses of all the routers between two devices.

Is traceroute a TCP or UDP?

On Unix-like operating systems, traceroute sends, by default, a sequence of User Datagram Protocol (UDP) packets, with destination port numbers ranging from 33434 to 33534; the implementations of traceroute shipped with Linux, FreeBSD, NetBSD, OpenBSD, DragonFly BSD, and macOS include an option to use ICMP Echo Request ...


2 Answers

What platform are you targeting? Here's a BSD flavor from OpenBSD source:

if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
    err(5, "icmp socket");
if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
    err(5, "raw socket");

On Linux, I believe, you need to use IP_RECVERR and recvmsg(2) with the MSG_ERRQUEUE, see ip(7).

like image 152
Nikolai Fetissov Avatar answered Nov 07 '22 04:11

Nikolai Fetissov


As far as setting the TTL is concerned, you can use setsockopt(). Here's an extract from the iputils' source for ping on Linux:

if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 1) == -1) {
    perror ("ping: can't set multicast time-to-live");
    exit(2);
}

if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL, &ittl, sizeof(ittl)) == -1) {
    perror ("ping: can't set unicast time-to-live");
    exit(2);
}
like image 2
thkala Avatar answered Nov 07 '22 02:11

thkala